/**
 * @file      downlink_manager.c
 * @brief
 * @version   1.0
 * @date      2023.12.14
 *
 * @copyright Copyright (c) 2018 UCchip Technology Co.,Ltd. All rights reserved.
 *
 * Change Logs:
 * Date          Author       Notes
 * 2023.12.14    ucchip       the first version
 *
 */

#include "downlink_manager.h"
#include "auth_manager.h"
#include "boot_api.h"
#include "config_api.h"
#include "config_boot.h"
#include "config_data.h"
#include "factory_api.h"
#include "gateway_manager.h"
#include "interaction_manager.h"
#include "led_manager.h"
#include "manager_queue_comm.h"
#include "module_queue_struct.h"
#include "msh.h"
#include "net_app.h"
#include "net_prot.h"
#include "netdev_manager.h"
#include "ota_manager.h"
#include "wiota_flashing.h"
#ifdef PKG_USING_PPP_DEVICE
#include "ppp_chat.h"
#endif
#include "roll_call_manager.h"
#include "serial_app.h"
#include "state_manager.h"
#include "time_slot_manager.h"
#include "tiny_base64.h"
#include "uc_coding.h"
#include "uc_hex.h"
#include "uc_wiota_api.h"
#include "ulog_app.h"
#include "userid_manager.h"
#include "watchdog_app.h"
#include "wiota_app.h"
#include "wiota_freq.h"
#include "zftp_app.h"
#include <rtthread.h>

#define DBG_ENABLE
#define DBG_SECTION_NAME "dl_mn"
#include "uc_log.h"

#define PG_CACHE_LIST_LEN 16
#define GET_PG_CACHE_LIST_KEY(ADDR) (ADDR & 0xF)

typedef struct
{
    rt_list_t node;      // 节点
    void *data;          // 数据
    unsigned int dev_id; // 设备地址
} paging_tx_node_t;

// 缓存唤醒并发送数据指令的数据，在收到唤醒终端上行后将该数据发送给终端
static rt_list_t g_paging_tx_cache_list[PG_CACHE_LIST_LEN];
// 参数设置立即生效标识，默认为1表示立即生效，0表示需要重启生效，对于想连续配置多个配置参数，但又不想配一个就重启，将该参数设置为0即可
static unsigned int g_immedicate_effect_flag = 1;
// 扫频停止开关，为1时，即使scan_times不为0，也停止
static unsigned char g_is_scan_stop = 0;
extern wiota_version_t g_wiota_version;

#define SET_CFG_PARA_NUM(ori_para, new_para, default_value, min_value, max_value, is_changed, is_invalid) \
    if (new_para == default_value)                                                                        \
    {                                                                                                     \
        new_para = ori_para;                                                                              \
        TRACE_W("set para is default");                                                                   \
    }                                                                                                     \
    else if (new_para < min_value || new_para > max_value)                                                \
    {                                                                                                     \
        is_invalid = 1;                                                                                   \
        is_changed = 0;                                                                                   \
        TRACE_W("set para is_invalid");                                                                   \
    }                                                                                                     \
    else                                                                                                  \
    {                                                                                                     \
        is_invalid = 0;                                                                                   \
        if (ori_para != new_para)                                                                         \
        {                                                                                                 \
            is_changed = 1;                                                                               \
        }                                                                                                 \
        else                                                                                              \
        {                                                                                                 \
            is_changed = 0;                                                                               \
        }                                                                                                 \
    }

#define SET_CFG_PARA_ARRAY(ori_para, new_para, default_para, para_len, is_changed) \
    if (0 == rt_memcmp(new_para, default_para, para_len))                          \
    {                                                                              \
        rt_memcpy(new_para, ori_para, para_len);                                   \
        TRACE_W("set para is default");                                            \
    }                                                                              \
    else                                                                           \
    {                                                                              \
        if (0 != rt_memcmp(new_para, ori_para, para_len))                          \
        {                                                                          \
            is_changed = 1;                                                        \
        }                                                                          \
        else                                                                       \
        {                                                                          \
            is_changed = 0;                                                        \
        }                                                                          \
    }

// 字符串的字段增加无效检测，当长度大于等于最大长度时为无效，为了保证字符串结尾一定为'\0'，避免设置这类参数时大于等于最大长度后出现乱码
#define SET_CFG_PARA_STR(ori_para, new_para, default_para, para_len, is_changed, is_invalid) \
    if (rt_strlen((const char *)new_para) >= para_len)                                       \
    {                                                                                        \
        is_invalid = 1;                                                                      \
        is_changed = 0;                                                                      \
        TRACE_W("set para is_invalid");                                                      \
    }                                                                                        \
    else if (0 == rt_memcmp(new_para, default_para, para_len))                               \
    {                                                                                        \
        rt_memcpy(new_para, ori_para, para_len);                                             \
        TRACE_W("set para is default");                                                      \
    }                                                                                        \
    else                                                                                     \
    {                                                                                        \
        if (0 != rt_memcmp(new_para, ori_para, para_len))                                    \
        {                                                                                    \
            is_changed = 1;                                                                  \
        }                                                                                    \
        else                                                                                 \
        {                                                                                    \
            is_changed = 0;                                                                  \
        }                                                                                    \
    }

/**
 * @brief 发送结果回调处理，释放内存
 *
 * @param data WIoTa app数据结构体指针
 */
static void wiota_exec_result(void *data)
{
    mng_to_wiota_data_t *wiota_data = data;

    if (RT_NULL != wiota_data->data)
        rt_free(wiota_data->data);
    if (RT_NULL != wiota_data)
        rt_free(wiota_data);
}

/**
 * @brief 根据终端dev_id映射对应的wiota_id
 *
 * @param dest              目标终端的设备地址
 * @param is_query_wiota_id 是否查询wiota id的标识
 * @param ts_fn             该终端所在的时隙
 *
 * @return unsigned int     非0表示查询到，0表示未查询到
 */
static unsigned int manager_get_wiota_addr(unsigned int dest, char is_query_wiota_id, unsigned int *ts_fn)
{
    unsigned int wiota_addr = 0;
    manager_address_t *reserve_data = RT_NULL;

    // 非透传模式下，根据设备id，映射到对应的WIoTa id进行发送
    if (UC_TRANSMISSION_MODE != uc_static_get_gateway_auth_cfg()->work_mode)
    {
        // WIoTa id规则，高位bit一定为1，如果不为1，则需要去查询
        if ((dest >> 31) & 0x01)
        {
            wiota_addr = dest;
        }
        else if (is_query_wiota_id)
        {
            // 根据设备id查询对应的WIoTa id，未查询到，则说明该id的IoTE未进行鉴权，属于非法id，不能发送数据
            reserve_data = manager_query_reserve_addr_by_dev_id(dest);

            if (reserve_data == RT_NULL)
            {
                TRACE_E("no device exists. dev id 0x%x", dest);
            }
            else
            {
                wiota_addr = (reserve_data->wiota_id | (1 << 31));
                *ts_fn = reserve_data->time_slot_fn;
            }
        }
    }
    else
    {
        // 透传模式不需要查询，直接发送
        wiota_addr = dest;
    }

    return wiota_addr;
}

/**
 * @brief 如果时分时收发模式，则已mng_to_wiota_data_t结构缓存下行单播数据
 *
 * @param data          编码后的数据
 * @param data_len      数据长度
 * @param wiota_id      用户ID
 * @param cur_time_slot 当前时隙
 * @return int          1表示不是分时模式，不需要缓存，2表示缓存满了，3表示缓存失败，0表示缓存成功
 */
int manager_cache_data_by_fn(unsigned char *data, unsigned int data_len, unsigned int wiota_id, unsigned int cur_time_slot)
{
    int res = 0;

    // 不是分时收发模式，不缓存数据
    if (0 == manager_get_is_ts_mode())
    {
        return 1;
    }

    // 缓存数据大小超出限制，不缓存数据
    if (0 != manager_cache_size_add(data_len))
    {
        return 2;
    }

    // 网关侧按照mng_to_wiota_data_t的形式缓存，方便统一处理发送结果和内存释放
    mng_to_wiota_data_t *cache_data = rt_malloc(sizeof(mng_to_wiota_data_t));
    RT_ASSERT(cache_data);
    rt_memset(cache_data, 0, sizeof(mng_to_wiota_data_t));

    cache_data->head.id = wiota_id;
    cache_data->head.result = WIOTA_SEND_DEFAULT;
    cache_data->head.cmd = WIOTA_APP_RS_SM_BY_FN;
    cache_data->data = data;
    cache_data->data_len = data_len;

    res = manager_cache_recv_send_data_by_fn((unsigned char *)cache_data, data_len, wiota_id, cur_time_slot);
    if (0 != res)
    {
        rt_free(cache_data);
    }

    return res;
}

/**
 * @brief 使用工作队列延迟发送paging tx携带的下行广播数据
 *
 * @param work      工作队列结构体指针
 * @param work_data 工作队列初始化时传入参数
 */
static void manager_send_paging_tx_bc_data_work(struct rt_work *work, void *work_data)
{
    if (0 != module_queue_communication(get_wiota_app_queue(),
                                        NET_APP_MODULE,
                                        WIOTA_APP_MODULE,
                                        WIOTA_APP_SEND_OTA,
                                        (void *)work_data))
    {
        manager_to_wiota_data_free((mng_to_wiota_data_t *)work_data);
        TRACE_E("send pt_bc_data error\n");
    }
    else
    {
        send_led_event(LED_WIOTA, LED_E_BLINK);
    }

    rt_free(work);
}

/**
 * @brief 提交工作队列，延迟发送paging tx携带的下行广播数据
 *
 * @param data       下行数据指针
 * @param data_len   下行数据长度
 * @param send_delay 延迟发送时间，单位ms
 * @return int       0表示成功，1表示失败
 */
static int manager_submit_paging_tx_bc_work(unsigned char *data, unsigned int data_len, unsigned int send_delay)
{
    mng_to_wiota_data_t *paging_tx_data = rt_malloc(sizeof(mng_to_wiota_data_t));
    if (RT_NULL == paging_tx_data)
    {
        return 1;
    }
    rt_memset(paging_tx_data, 0, sizeof(mng_to_wiota_data_t));

    paging_tx_data->head.result_function = wiota_exec_result;
    paging_tx_data->head.cmd = WIOTA_APP_SEND_OTA;
    paging_tx_data->data = data;
    paging_tx_data->data_len = data_len;

    // 使用工作队列延迟send_delay ms发送
    struct rt_work *pt_bc_work = rt_malloc(sizeof(struct rt_work));
    if (RT_NULL == pt_bc_work)
    {
        rt_free(paging_tx_data);
        return 2;
    }

    rt_work_init(pt_bc_work, manager_send_paging_tx_bc_data_work, (void *)paging_tx_data);
    rt_work_submit(pt_bc_work, send_delay);
    TRACE_D("submit pt_bc_work, delay %u", send_delay);

    return 0;
}

/**
 * @brief 初始化paging tx缓存列表
 *
 */
void manager_paging_tx_cache_list_init(void)
{
    for (int i = 0; i < PG_CACHE_LIST_LEN; i++)
    {
        rt_list_init(&g_paging_tx_cache_list[i]);
    }
}

/**
 * @brief 反初始化paging tx缓存列表
 *
 */
void manager_paging_tx_cache_list_deinit(void)
{
    for (int i = 0; i < PG_CACHE_LIST_LEN; i++)
    {
        rt_list_t *cache_list = &g_paging_tx_cache_list[i];
        rt_list_t *next_node = cache_list->next;
        paging_tx_node_t *paging_tx_node = RT_NULL;

        while (next_node != cache_list)
        {
            paging_tx_node = (paging_tx_node_t *)rt_list_entry(next_node, paging_tx_node_t, node);
            if (paging_tx_node)
            {
                mng_to_wiota_data_t *paging_tx_data = (mng_to_wiota_data_t *)paging_tx_node->data;
                if (paging_tx_data)
                {
                    manager_to_wiota_data_free((mng_to_wiota_data_t *)paging_tx_data);
                }
                rt_free(paging_tx_node);
            }
            next_node = next_node->next;
        }

        // TRACE_D("deinit paging_tx_cache_list[%d] %d\n", i, rt_list_len(&g_paging_tx_cache_list[i]));
    }
}

/**
 * @brief 获取是否有缓存的paging tx单播数据
 *
 * @param dev_id 设备ID
 * @return int   1表示有缓存的paging tx数据，0表示没有缓存的paging tx数据
 */
int manager_get_cache_paging_tx_uc_data(unsigned int dev_id)
{
    rt_list_t *cache_list = &g_paging_tx_cache_list[GET_PG_CACHE_LIST_KEY(dev_id)];
    rt_list_t *next_node = cache_list->next;
    paging_tx_node_t *paging_tx_node = RT_NULL;

    while (next_node != cache_list)
    {
        paging_tx_node = (paging_tx_node_t *)rt_list_entry(next_node, paging_tx_node_t, node);
        if (paging_tx_node && paging_tx_node->dev_id == dev_id)
        {
            return 1;
        }
        next_node = next_node->next;
    }

    return 0;
}

/**
 * @brief 发送缓存的paging tx单播数据
 *
 * @param dev_id 设备ID
 * @return int   0表示成功，1表示失败
 */
int manager_send_cache_paging_tx_uc_data(unsigned int dev_id)
{
    rt_list_t *cache_list = &g_paging_tx_cache_list[GET_PG_CACHE_LIST_KEY(dev_id)];
    rt_list_t *next_node = cache_list->next;
    paging_tx_node_t *paging_tx_node = RT_NULL;

    while (next_node != cache_list)
    {
        paging_tx_node = (paging_tx_node_t *)rt_list_entry(next_node, paging_tx_node_t, node);
        if (paging_tx_node && paging_tx_node->dev_id == dev_id)
        {
            mng_to_wiota_data_t *paging_tx_data = (mng_to_wiota_data_t *)paging_tx_node->data;
            paging_tx_data->head.id = manager_query_wiota_id_by_dev_id(dev_id); // 重新找一下wiota id，防止网关重启了，对应信息不对

            if (0 != module_queue_communication(get_wiota_app_queue(),
                                                NET_APP_MODULE,
                                                WIOTA_APP_MODULE,
                                                WIOTA_APP_MSG,
                                                (void *)paging_tx_data))
            {
                manager_to_wiota_data_free((mng_to_wiota_data_t *)paging_tx_data);
                TRACE_E("send pt_uc_data error1\n");
            }
            else
            {
                send_led_event(LED_WIOTA, LED_E_BLINK);
                next_node = next_node->next;
                rt_list_remove(&paging_tx_node->node);
                rt_free(paging_tx_node);
                continue;
            }
        }
        next_node = next_node->next;
    }

    return 0;
}

/**
 * @brief 缓存paging tx携带的单播数据
 *
 * @param data       下行数据指针
 * @param data_len   下行数据长度
 * @param wiota_addr WIoTA地址
 * @param dev_id     设备ID
 * @return int       0表示成功，1表示失败
 */
static int manager_cache_paging_tx_uc_data(unsigned char *data, unsigned int data_len, unsigned int wiota_addr, unsigned int dev_id)
{
    mng_to_wiota_data_t *paging_tx_data = rt_malloc(sizeof(mng_to_wiota_data_t));
    if (RT_NULL == paging_tx_data)
    {
        return 1;
    }
    rt_memset(paging_tx_data, 0, sizeof(mng_to_wiota_data_t));

    paging_tx_data->head.result_function = wiota_exec_result;
    paging_tx_data->head.cmd = WIOTA_APP_MSG;
    paging_tx_data->head.id = wiota_addr;
    paging_tx_data->data = data;
    paging_tx_data->data_len = data_len;

    paging_tx_node_t *paging_tx_node = rt_malloc(sizeof(paging_tx_node_t));
    if (RT_NULL == paging_tx_node)
    {
        rt_free(paging_tx_data);
        return 1;
    }
    rt_memset(paging_tx_node, 0, sizeof(paging_tx_node_t));

    paging_tx_node->data = paging_tx_data;
    paging_tx_node->dev_id = dev_id;

    rt_list_insert_after(&g_paging_tx_cache_list[GET_PG_CACHE_LIST_KEY(dev_id)], &paging_tx_node->node);

    return 0;
}

/**
 * @brief 处理网络下行用户数据消息
 *
 * @param from_module       来自哪个线程的用户数据，net、web、serial、serial debug或BT
 * @param net_data          网络下行数据指针
 * @param is_paging_tx_data 是否为paging tx的数据
 * @param send_delay        is_paging_tx_data为1时有效，广播延迟发送时间，单位ms
 */
static void manager_handle_dl_user_data_msg(int from_module, net_dl_userdata_t *net_data, int is_paging_tx_data, unsigned int send_delay)
{
    char *bc_data = RT_NULL;
    unsigned int bc_len = 0;
    char *uc_data = RT_NULL;
    unsigned int uc_len = 0;
    unsigned char if_free_bc = 1;
    unsigned char if_free_uc = 1;
    unsigned char is_only_header = 0;
    unsigned char *output_data;
    unsigned int output_len;
    unsigned int wiota_addr;
    app_ps_header_t ps_header = {0};
    unsigned char dl_data_print = uc_static_get_gateway_data_cfg()->dl_data_print;
    unsigned char gw_verity = uc_static_get_gateway_auth_cfg()->gw_verity;
    unsigned int gw_dev_id = uc_static_get_gateway_base_cfg()->dev_id;
    unsigned int ts_fn = 0;
    int res = 0;

    // 入参检查
    if (RT_NULL == net_data)
    {
        TRACE_E("net_data is NULL");
        return;
    }

    // id管理未初始化，不能发送数据
    if (USERID_MANAGE_INIT != manager_get_userid_manager_state())
    {
        TRACE_E("addr_state is not init, not require to send data");
        net_dl_userdata_free(net_data);
        return;
    }

    // 如果处于扫频状态，为同一线程阻塞状态，无需判断manager_get_scan_freq_state()

    ps_header.cmd_type = net_data->head.cmd;

    if (ps_header.cmd_type != IOTE_USER_DATA &&
        ps_header.cmd_type != IOTE_LOOPDATA &&
        ps_header.cmd_type != IOTE_VERSION_REQ)
    {
        TRACE_E("net_dl cmd_type %d error", ps_header.cmd_type);
        net_dl_userdata_free(net_data);
        return;
    }

    // IOTE_VERSION_REQ只有头，没有数据
    if (ps_header.cmd_type == IOTE_VERSION_REQ)
    {
        is_only_header = 1;
    }

    // 开启网关验证后，下行数据添加src_addr，终端收到后做验证
    if (gw_verity)
    {
        app_set_header_property(PRO_SRC_ADDR, 1, &ps_header.property);
        ps_header.addr.src_addr = gw_dev_id;
    }

    app_set_header_property(PRO_COMPRESS_FLAG, 1, &ps_header.property);

    // 广播编码，并发送到WIoTa APP线程
    if (!is_only_header && RT_NULL != net_data->broadcast_data) // 原生数据根据fmt进行解码
    {
        // Base64 解码
        if (rt_strncmp(net_data->fmt, "base64", 6) == 0)
        {
            string_base64_decode(&bc_data, &bc_len, net_data->broadcast_data, net_data->broadcast_len);
        }
        // Hex 解码
        else if (rt_strncmp(net_data->fmt, "hex", 3) == 0)
        {
            string_hex_decode(&bc_data, &bc_len, net_data->broadcast_data, net_data->broadcast_len);
        }
        else
        {
            // 其他均为String 解码
            bc_data = net_data->broadcast_data;
            bc_len = net_data->broadcast_len;
            if_free_bc = 0;
        }
    }
    else
    {
        if_free_bc = 0;
    }

    if (bc_data && bc_len && dl_data_print)
    {
        rt_kprintf("dl_bc_data len %d\n", bc_len);
        manager_printf_data_hex(bc_data, bc_len);
    }

    if ((is_only_header && net_data->head.dest_num == 0) || (bc_data && bc_len))
    {
        if (0 == app_data_coding(&ps_header, bc_data, bc_len, &output_data, &output_len))
        {
            if (!is_paging_tx_data)
            {
                if (0 != manager_send_to_wiota(from_module,
                                               WIOTA_APP_SEND_OTA,
                                               net_data->order_business,
                                               net_data->head.src_addr,
                                               0,
                                               output_data,
                                               output_len,
                                               wiota_exec_result))
                {
                    rt_free(output_data);
                }
                send_led_event(LED_WIOTA, LED_E_BLINK);
            }
            else
            {
                // 如果paging tx携带的是广播，就在连续信号发送完成后就发送该广播数据
                if (0 != manager_submit_paging_tx_bc_work(output_data, output_len, send_delay))
                {
                    rt_free(output_data);
                }
            }
        }
        else
        {
            TRACE_E("net_dl broadcast_data coding error");
        }
    }

    // 遍历发送单播
    if (!is_only_header && RT_NULL != net_data->unicast_data) // 原生数据根据fmt进行解码
    {
        // Base64 解码
        if (rt_strncmp(net_data->fmt, "base64", 6) == 0)
        {
            string_base64_decode(&uc_data, &uc_len, net_data->unicast_data, net_data->unicast_len);
        }
        // Hex 解码
        else if (rt_strncmp(net_data->fmt, "hex", 3) == 0)
        {
            string_hex_decode(&uc_data, &uc_len, net_data->unicast_data, net_data->unicast_len);
        }
        else
        {
            // 其他均为String 解码
            uc_data = net_data->unicast_data;
            uc_len = net_data->unicast_len;
            if_free_uc = 0;
        }
    }
    else
    {
        if_free_uc = 0;
    }

    if ((is_only_header && net_data->head.dest_num > 0) || (uc_data && uc_len))
    {
        TRACE_D("dl_uc_data dest_num %d", net_data->head.dest_num);
        if (net_data->head.dest_num == 0)
        {
            TRACE_E("dl_uc_data dst is null");
        }
        for (int num = 0; num < net_data->head.dest_num; num++)
        {
            if (uc_data && uc_len && dl_data_print)
            {
                TRACE_D("dl_uc_data id %d, len %d", net_data->head.dest_addr[num], uc_len);
                manager_printf_data_hex(uc_data, uc_len);
            }
            wiota_addr = manager_get_wiota_addr(net_data->head.dest_addr[num], 1, &ts_fn);
            if (wiota_addr == 0 && !is_paging_tx_data) // 如果是paging tx的缓存数据，即使wiota addr未找到（网关重启了），也要缓存
            {
                continue;
            }
            // 单播编码，并发送到WIoTa APP线程
            if (0 == app_data_coding(&ps_header, uc_data, uc_len, &output_data, &output_len))
            {
                if (!is_paging_tx_data)
                {
                    // 如果时分时收发模式，单播数据需要缓存
                    res = manager_cache_data_by_fn(output_data, output_len, wiota_addr, ts_fn);
                    if (res == 1) // 不是分时模式，不需要缓存
                    {
                        if (0 != manager_send_to_wiota(from_module,
                                                       WIOTA_APP_MSG,
                                                       net_data->order_business,
                                                       net_data->head.src_addr,
                                                       wiota_addr,
                                                       output_data,
                                                       output_len,
                                                       wiota_exec_result))
                        {
                            rt_free(output_data);
                        }
                        send_led_event(LED_WIOTA, LED_E_BLINK);
                    }
                    else if (res == 2 || res == 3) // 缓存满了res==2或缓存失败res==3
                    {
                        rt_free(output_data);
                    }
                    else // 缓存成功res==0
                    {
                        // do nothing
                    }
                }
                else
                {
                    // 如果paging tx携带的是单播，则缓存该单播数据，并在收到唤醒终端的上行消息后将缓存数据发送给终端
                    if (0 != manager_cache_paging_tx_uc_data(output_data, output_len, wiota_addr, net_data->head.dest_addr[num]))
                    {
                        rt_free(output_data);
                    }
                }
            }
            else
            {
                TRACE_E("net_dl unicast_data coding error");
            }
        }
    }

    if (if_free_bc) // 为string时，不需要释放bc_data
    {
        rt_free(bc_data);
    }

    if (if_free_uc) // 为string时，不需要释放uc_data
    {
        rt_free(uc_data);
    }
    // 处理完成后，释放net_data
    net_dl_userdata_free(net_data);

    return;
}

/**
 * @brief 获取WIoTa版本信息
 *
 * @return wiota_version_t* WIoTa版本信息结构体指针
 */
static wiota_version_t *get_wiota_version(void)
{
    wiota_version_t *version = rt_malloc(sizeof(wiota_version_t));
    RT_ASSERT(version);
    rt_memset(version, 0, sizeof(wiota_version_t));

    rt_memcpy(version, &g_wiota_version, sizeof(wiota_version_t));

    if (WIOTA_ONLINE != manager_get_wiota_state())
    {
        TRACE_E("wiota_state is offline, WIoTa version is null");
    }
    else
    {
        TRACE_D("wiota_version %s", version->uc8088_version);
        TRACE_D("git_info %s", version->git_info_8088);
        TRACE_D("make_time %s", version->make_time_8088);
        TRACE_D("cce_version %u", version->cce_version);
    }

    return version;
}

/**
 * @brief 获取WIoTa子系统配置信息
 *
 * @return wiota_sys_cfg_t* WIoTa子系统配置信息结构体指针
 */
static wiota_sys_cfg_t *get_wiota_sys_cfg(void)
{
    wiota_sys_cfg_t *sys_cfg = rt_malloc(sizeof(wiota_sys_cfg_t));
    RT_ASSERT(sys_cfg);
    rt_memset(sys_cfg, 0, sizeof(wiota_sys_cfg_t));

    rt_memcpy(sys_cfg, uc_static_get_wiota_sys_cfg(), sizeof(wiota_sys_cfg_t));
    TRACE_D("get_wiota_sys_cfg: symbol_length %d, dlul_ratio %d, group_number %d, subsystem_id %u",
            sys_cfg->symbol_length, sys_cfg->dlul_ratio, sys_cfg->group_number, sys_cfg->subsystem_id);

    return sys_cfg;
}

/**
 * @brief 设置WIoTa子系统配置信息
 *
 * @param sys_cfg        WIoTa子系统配置信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_sys_cfg(wiota_sys_cfg_t *sys_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    unsigned char is_changed[5] = {0};
    unsigned char is_invalid[5] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    wiota_sys_cfg_t *ori_cfg = uc_static_get_wiota_sys_cfg();
    unsigned char sym_len_max = sys_cfg->bt_value == UC_BT_VALUE_03 ? UC_SYMBOL_LEN_1024 : UC_SYMBOL_LEN_256;

    SET_CFG_PARA_NUM(ori_cfg->symbol_length, sys_cfg->symbol_length, 0xFF, UC_SYMBOL_LEN_128, sym_len_max, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->dlul_ratio, sys_cfg->dlul_ratio, 0xFF, UC_DLUL_RATIO_1_1, UC_DLUL_RATIO_1_2, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->group_number, sys_cfg->group_number, 0xFF, UC_GROUP_NUM_1, UC_GROUP_NUM_8, is_changed[2], is_invalid[2])
    SET_CFG_PARA_NUM(ori_cfg->bt_value, sys_cfg->bt_value, 0xFF, UC_BT_VALUE_12, UC_BT_VALUE_03, is_changed[3], is_invalid[3])
    SET_CFG_PARA_NUM(ori_cfg->subsystem_id, sys_cfg->subsystem_id, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[4], is_invalid[4])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4])
    {
        *set_res = 1;
    }
    else
    {
        if (sys_cfg->dlul_ratio == 1 && sys_cfg->group_number == 0)
        {
            *set_res = 1;
            TRACE_E("sys_cfg error, set dlul_ratio to 0 or group_number to 1");
        }
        else if (sys_cfg->bt_value == UC_BT_VALUE_12 && sys_cfg->symbol_length > UC_SYMBOL_LEN_256)
        {
            *set_res = 1;
            TRACE_E("sys_cfg error, only support symbol_length <= 1 when bt_value is 0");
        }
        else
        {
            if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4])
            {
                if (is_changed[0]) // symbol_length改变，初始化连接态时间
                {
                    uc_static_active_time_init(sys_cfg->symbol_length);
                }
                uc_static_set_wiota_sys_cfg(sys_cfg);
                *is_reboot = 1;
                *is_save_static = 1;
            }
        }
    }

    TRACE_D("set_wiota_sys_cfg: symbol_length %d, dlul_ratio %d, group_number %d, subsystem_id %u",
            sys_cfg->symbol_length, sys_cfg->dlul_ratio, sys_cfg->group_number, sys_cfg->subsystem_id);

    rt_free(sys_cfg);

    return set_res;
}

/**
 * @brief 获取WIoTa连接态时间配置
 *
 * @return wiota_act_cfg_t* WIoTa连接态时间配置结构体指针
 */
static wiota_act_cfg_t *get_wiota_act_cfg(void)
{
    wiota_act_cfg_t *act_cfg = rt_malloc(sizeof(wiota_act_cfg_t));
    RT_ASSERT(act_cfg);
    rt_memset(act_cfg, 0, sizeof(wiota_act_cfg_t));

    rt_memcpy(act_cfg, uc_static_get_wiota_act_cfg(), sizeof(wiota_act_cfg_t));
    TRACE_D("get_wiota_act_cfg: active_time %u", act_cfg->active_time);

    return act_cfg;
}

/**
 * @brief 设置WIoTa连接态时间配置
 *
 * @param act_cfg        WIoTa连接态时间配置结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_act_cfg(wiota_act_cfg_t *act_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed = 0;
    unsigned char is_invalid = 0;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    if (WIOTA_ONLINE != manager_get_wiota_state())
    {
        TRACE_W("wiota_state is offline, unable to set active time");
        *set_res = 1;
    }
    else
    {
        wiota_act_cfg_t *ori_cfg = uc_static_get_wiota_act_cfg();
        SET_CFG_PARA_NUM(ori_cfg->active_time, act_cfg->active_time, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed, is_invalid)

        if (is_invalid)
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed)
            {
                uc_static_set_wiota_act_cfg(act_cfg);
                uc_wiota_set_active_time(act_cfg->active_time);
                *is_save_static = 1;
            }
        }
    }

    TRACE_D("set_wiota_act_cfg: active_time %u", act_cfg->active_time);

    rt_free(act_cfg);

    return set_res;
}

/**
 * @brief 获取WIoTa频点配置信息
 *
 * @return wiota_freq_cfg_t* 频点信息结构体指针
 */
static wiota_freq_cfg_t *get_wiota_freq_cfg(void)
{
    int out_len = 0;
    char *out = rt_calloc(1, 128);
    wiota_freq_cfg_t *freq_cfg = rt_malloc(sizeof(wiota_freq_cfg_t));
    RT_ASSERT(out);
    RT_ASSERT(freq_cfg);
    rt_memset(freq_cfg, 0, sizeof(wiota_freq_cfg_t));

    rt_memcpy(freq_cfg, uc_static_get_wiota_freq_cfg(), sizeof(wiota_freq_cfg_t));

    out_len = rt_snprintf(out, 128, "get_wiota_freq_cfg: current_freq %d [", freq_cfg->current_freq);
    for (int i = 0; i < 16; i++)
    {
        out_len += rt_snprintf(out + out_len, 128 - out_len, "%d ", freq_cfg->freq_list[i]);
    }
    rt_snprintf(out + out_len, 128 - out_len, "]");
    TRACE_D("%s", out);

    if (RT_NULL != out)
    {
        rt_free(out);
    }

    return freq_cfg;
}

/**
 * @brief 设置WIoTa频点配置
 *
 * @param freq_cfg       频点信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_auth_change 是否发送鉴权改变信息标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_freq_cfg(wiota_freq_cfg_t *freq_cfg, unsigned char *is_reboot, unsigned char *is_auth_change, unsigned char *is_save_static)
{
    unsigned char default_para[16] = {0};
    unsigned int is_changed = 0;
    unsigned int is_invalid = 0;

    int out_len = 0;
    char *out = rt_calloc(1, 128);
    RT_ASSERT(out);

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    // if (WIOTA_ONLINE != manager_get_wiota_state())
    // {
    //     TRACE_E("wiota_state is offline, unable to send auth change info");
    //     *set_res = 1;
    // }
    // else
    {
        rt_memset(default_para, 0xFF, sizeof(default_para));
        wiota_freq_cfg_t *ori_cfg = uc_static_get_wiota_freq_cfg();

        freq_cfg->current_freq = ori_cfg->current_freq; // 只读
        SET_CFG_PARA_ARRAY(ori_cfg->freq_list, freq_cfg->freq_list, default_para, sizeof(freq_cfg->freq_list), is_changed)
        if (is_changed)
        {
            uc_static_set_wiota_freq_cfg(freq_cfg);
            *is_auth_change = 1;
            *is_save_static = 1;
            *is_reboot = 1;
        }
    }

    out_len = rt_snprintf(out, 128, "set_wiota_freq_cfg: [");
    for (int i = 0; i < sizeof(freq_cfg->freq_list); i++)
    {
        out_len += rt_snprintf(out + out_len, 128 - out_len, "%d ", freq_cfg->freq_list[i]);
    }
    rt_snprintf(out + out_len, 128 - out_len, "]");
    TRACE_D("%s", out);

    if (RT_NULL != out)
    {
        rt_free(out);
    }

    rt_free(freq_cfg);

    return set_res;
}

/**
 * @brief 获取WIoTa功率配置
 *
 * @return wiota_power_cfg_t* WIoTa功率信息结构体指针
 */
static wiota_power_cfg_t *get_wiota_power_cfg(void)
{
    wiota_power_cfg_t *power_cfg = rt_malloc(sizeof(wiota_power_cfg_t));
    RT_ASSERT(power_cfg);
    rt_memset(power_cfg, 0, sizeof(wiota_power_cfg_t));

    rt_memcpy(power_cfg, uc_static_get_wiota_power_cfg(), sizeof(wiota_power_cfg_t));
    TRACE_D("get_wiota_power_cfg: power %d", power_cfg->power);

    return power_cfg;
}

/**
 * @brief 设置WIoTa功率配置
 *
 * @param power_cfg      WIoTa功率信息结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_power_cfg(wiota_power_cfg_t *power_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed = 0;
    unsigned char is_invalid = 0;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    if (WIOTA_ONLINE != manager_get_wiota_state())
    {
        TRACE_E("wiota_state is offline, unable to set tx power");
        *set_res = 1;
    }
    else
    {
        wiota_power_cfg_t *ori_cfg = uc_static_get_wiota_power_cfg();

        SET_CFG_PARA_NUM(ori_cfg->power, power_cfg->power, 0xFF, 0, 29, is_changed, is_invalid)

        if (is_invalid)
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed)
            {
                uc_static_set_wiota_power_cfg(power_cfg);
#if 1 // v1.3硬件问题，暂时限制最大功率为22，但静态数据不改
                signed char power = power_cfg->power;
                if (power > 22)
                {
                    power = 22;
                }
                uc_wiota_set_ap_tx_power(power);
#else
                uc_wiota_set_ap_tx_power(power_cfg->power);
#endif
                *is_save_static = 1;
            }
        }
    }

    TRACE_D("set_wiota_power_cfg: power %d", power_cfg->power);

    rt_free(power_cfg);

    return set_res;
}

/**
 * @brief 获取WIoTa速率模式配置信息
 *
 * @return wiota_rate_cfg_t* WIoTa速率模式配置信息结构体指针
 */
static wiota_rate_cfg_t *get_wiota_rate_cfg(void)
{
    wiota_rate_cfg_t *rate_cfg = rt_malloc(sizeof(wiota_rate_cfg_t));
    RT_ASSERT(rate_cfg);
    rt_memset(rate_cfg, 0, sizeof(wiota_rate_cfg_t));

    rt_memcpy(rate_cfg, uc_static_get_wiota_rate_cfg(), sizeof(wiota_rate_cfg_t));
    TRACE_D("get_wiota_rate_cfg: uc_mcs %d, mid %d, high %d, bc_mcs %d, crc_type %d, bc_round %d, uc_resend %d",
            rate_cfg->unicast_mcs, rate_cfg->mid_mode_state, rate_cfg->high_mode_state, rate_cfg->broadcast_mcs, rate_cfg->crc_type,
            rate_cfg->bc_send_round, rate_cfg->uc_resend_times);

    return rate_cfg;
}

/**
 * @brief 设置WIoTa速率模式配置信息
 *
 * @param rate_cfg       WIoTa速率模式配置信息结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_rate_cfg(wiota_rate_cfg_t *rate_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed[7] = {0};
    unsigned char is_invalid[7] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    if (WIOTA_ONLINE != manager_get_wiota_state())
    {
        TRACE_E("wiota_state is offline, unable to set mcs cfg");
        *set_res = 1;
    }
    else
    {
        wiota_rate_cfg_t *ori_cfg = uc_static_get_wiota_rate_cfg();
        unsigned char uc_mcs_max = rate_cfg->unicast_mcs == UC_MCS_LEVEL_AUTO ? UC_MCS_LEVEL_AUTO : uc_static_get_max_mcs(1);

        SET_CFG_PARA_NUM(ori_cfg->unicast_mcs, rate_cfg->unicast_mcs, 0xFF, UC_MCS_LEVEL_0, uc_mcs_max, is_changed[0], is_invalid[0])
        SET_CFG_PARA_NUM(ori_cfg->mid_mode_state, rate_cfg->mid_mode_state, 0xFF, 0, 1, is_changed[1], is_invalid[1])
        SET_CFG_PARA_NUM(ori_cfg->high_mode_state, rate_cfg->high_mode_state, 0xFFFF, 0, UC_DL_MAX_LEN, is_changed[2], is_invalid[2])
        SET_CFG_PARA_NUM(ori_cfg->broadcast_mcs, rate_cfg->broadcast_mcs, 0xFF, UC_MCS_LEVEL_0, uc_static_get_max_mcs(0), is_changed[3], is_invalid[3])
        SET_CFG_PARA_NUM(ori_cfg->crc_type, rate_cfg->crc_type, 0xFF, 0, 1, is_changed[4], is_invalid[4])
        SET_CFG_PARA_NUM(ori_cfg->bc_send_round, rate_cfg->bc_send_round, 0xFF, 1, 3, is_changed[5], is_invalid[5])
        SET_CFG_PARA_NUM(ori_cfg->uc_resend_times, rate_cfg->uc_resend_times, 0xFF, 0, 3, is_changed[6], is_invalid[6])
        // 如果开启了分时收发策略，则不允许修改单播速率、网关侧的单播重发次数，只能通过分时收发配置
        if (uc_static_get_slot_send_cfg()->data_transport_period && uc_static_get_gateway_auth_cfg()->work_mode == UC_TRANSMISSION_TIME_SLOT_MODE)
        {
            rate_cfg->unicast_mcs = ori_cfg->unicast_mcs;
            rate_cfg->uc_resend_times = ori_cfg->uc_resend_times;
        }

        if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] || is_invalid[5] || is_invalid[6])
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5] || is_changed[6])
            {
                uc_static_set_wiota_rate_cfg(rate_cfg);
                if (is_changed[0])
                {
                    uc_wiota_set_data_rate(UC_RATE_NORMAL, rate_cfg->unicast_mcs);
                }

                if (is_changed[1])
                {
                    uc_wiota_set_data_rate(UC_RATE_MID, rate_cfg->mid_mode_state);
                }

                if (is_changed[2])
                {
                    uc_wiota_set_data_rate(UC_RATE_HIGH, rate_cfg->high_mode_state);
                }

                if (is_changed[3])
                {
                    uc_wiota_set_broadcast_mcs(rate_cfg->broadcast_mcs);
                }

                if (is_changed[4])
                {
                    uc_wiota_set_data_rate(UC_RATE_CRC_TYPE, rate_cfg->crc_type);
                }

                if (is_changed[5])
                {
                    uc_wiota_set_broadcast_send_round(rate_cfg->bc_send_round);
                }
                *is_save_static = 1;
            }
        }
    }

    TRACE_D("set_wiota_rate_cfg: uc_mcs %d, mid %d, high %d, bc_mcs %d, crc_type %d, bc_round %d, uc_resend %d",
            rate_cfg->unicast_mcs, rate_cfg->mid_mode_state, rate_cfg->high_mode_state, rate_cfg->broadcast_mcs, rate_cfg->crc_type,
            rate_cfg->bc_send_round, rate_cfg->uc_resend_times);

    rt_free(rate_cfg);

    return set_res;
}

/**
 * @brief 获取WIoTa paging tx空中唤醒配置
 *
 * @return wiota_paging_tx_cfg_t* WIoTa paging tx空中唤醒配置信息结构体指针
 */
static wiota_paging_tx_cfg_t *get_wiota_paging_tx_cfg(void)
{
    wiota_paging_tx_cfg_t *paging_tx_cfg = rt_malloc(sizeof(wiota_paging_tx_cfg_t));
    RT_ASSERT(paging_tx_cfg);
    rt_memset(paging_tx_cfg, 0, sizeof(wiota_paging_tx_cfg_t));

    rt_memcpy(paging_tx_cfg, uc_static_get_wiota_paging_tx_cfg(), sizeof(wiota_paging_tx_cfg_t));
    TRACE_D("get_wiota_paging_tx_cfg: freq %d, symbol_length %d, awaken_id 0x%x, send_time %u, mode %d",
            paging_tx_cfg->freq, paging_tx_cfg->symbol_length, paging_tx_cfg->awaken_id, paging_tx_cfg->send_time, paging_tx_cfg->mode);

    return paging_tx_cfg;
}

/**
 * @brief 设置WIoTa paging tx空中唤醒并发送数据
 *
 * @param paging_tx_cfg  WIoTa paging tx空中唤醒并发送数据或唤醒结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_paging_tx_cfg(void *paging_tx_cfg, int from_module, unsigned char *is_save_static)
{
    unsigned char is_changed[5] = {0};
    unsigned char is_invalid[5] = {0};
    wiota_paging_tx_and_data_t *paging_tx_and_send = RT_NULL;
    wiota_paging_tx_cfg_t *paging_tx = RT_NULL;
    net_dl_userdata_t *user_data = RT_NULL;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    // 远程支持唤醒并发送，工具端只支持唤醒
    if (from_module == NET_APP_MODULE)
    {
        paging_tx_and_send = (wiota_paging_tx_and_data_t *)paging_tx_cfg;
        paging_tx = paging_tx_and_send->paging_tx;
        user_data = paging_tx_and_send->user_data;
    }
    else
    {
        paging_tx = (wiota_paging_tx_cfg_t *)paging_tx_cfg;
    }

    if (WIOTA_ONLINE != manager_get_wiota_state())
    {
        TRACE_E("wiota_state is offline, unable to send paging tx");
        *set_res = 1;
    }
    else
    {
        wiota_paging_tx_cfg_t *ori_cfg = uc_static_get_wiota_paging_tx_cfg();

        SET_CFG_PARA_NUM(ori_cfg->freq, paging_tx->freq, 0xFF, 1, 200, is_changed[0], is_invalid[0])
        SET_CFG_PARA_NUM(ori_cfg->symbol_length, paging_tx->symbol_length, 0xFF, UC_SYMBOL_LEN_128, UC_SYMBOL_LEN_1024, is_changed[1], is_invalid[1])
        SET_CFG_PARA_NUM(ori_cfg->awaken_id, paging_tx->awaken_id, 0xFFFF, 1, 0xFFFE, is_changed[2], is_invalid[2])
        SET_CFG_PARA_NUM(ori_cfg->send_time, paging_tx->send_time, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[3], is_invalid[3])
        SET_CFG_PARA_NUM(ori_cfg->mode, paging_tx->mode, 0xFF, 0, 1, is_changed[4], is_invalid[4])

        if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4])
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4])
            {
                uc_static_set_wiota_paging_tx_cfg(paging_tx);
                *is_save_static = 1;
            }
            if (0 == module_queue_communication(module_get_queue(WIOTA_APP_MODULE),
                                                GATEWAY_MANAGER_MODULE,
                                                WIOTA_APP_MODULE,
                                                WIOTA_APP_PAGING_TX,
                                                RT_NULL))
            {
                // 唤醒并发送数据
                if (user_data)
                {
                    manager_handle_dl_user_data_msg(NET_APP_MODULE, user_data, 1, user_data->send_delay);
                }
            }
        }
    }

    TRACE_D("set_wiota_paging_tx_cfg: freq %d, symbol_length %d, awaken_id %u, send_time %u, mode %d",
            paging_tx->freq, paging_tx->symbol_length, paging_tx->awaken_id, paging_tx->send_time, paging_tx->mode);

    // user_data不管为不为空都不需要在这里释放
    rt_free(paging_tx);
    // 如果为工具设置的paging_tx和paging_tx_cfg为同一个地址，远程设置的才需要释放
    if (from_module == NET_APP_MODULE)
    {
        rt_free(paging_tx_cfg);
    }

    return set_res;
}

/**
 * @brief 获取WIoTa sync paging空中唤醒配置
 *
 * @return wiota_sync_paging_cfg_t* WIoTa sync paging空中唤醒配置信息结构体指针
 */
static wiota_sync_paging_cfg_t *get_wiota_sync_paging_cfg(void)
{
    wiota_sync_paging_cfg_t *sync_paging_cfg = rt_malloc(sizeof(wiota_sync_paging_cfg_t));
    RT_ASSERT(sync_paging_cfg);
    rt_memset(sync_paging_cfg, 0, sizeof(wiota_sync_paging_cfg_t));

    rt_memcpy(sync_paging_cfg, uc_static_get_wiota_sync_paging_cfg(), sizeof(wiota_sync_paging_cfg_t));
    TRACE_D("get_wiota_sync_paging_cfg: dev_id %u, period %u, send_round %u, continue_fn %u",
            sync_paging_cfg->dev_id, sync_paging_cfg->detection_period, sync_paging_cfg->send_round, sync_paging_cfg->continue_fn);

    return sync_paging_cfg;
}

/**
 * @brief 设置WIoTa sync paging空中唤醒配置
 *
 * @param sync_paging_cfg WIoTa sync paging空中唤醒配置信息结构体指针
 * @param is_save_static  是否保存静态数据标识
 * @return char*          设置结果
 */
static char *set_wiota_sync_paging_cfg(wiota_sync_paging_cfg_t *sync_paging_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed[4] = {0};
    unsigned char is_invalid[4] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    if (WIOTA_ONLINE != manager_get_wiota_state())
    {
        TRACE_E("wiota_state is offline, unable to send sync paging");
        *set_res = 1;
    }
    else
    {
        wiota_sync_paging_cfg_t *ori_cfg = uc_static_get_wiota_sync_paging_cfg();

        SET_CFG_PARA_NUM(ori_cfg->dev_id, sync_paging_cfg->dev_id, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[0], is_invalid[0])
        SET_CFG_PARA_NUM(ori_cfg->detection_period, sync_paging_cfg->detection_period, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[1], is_invalid[1])
        SET_CFG_PARA_NUM(ori_cfg->send_round, sync_paging_cfg->send_round, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[2], is_invalid[2])
        SET_CFG_PARA_NUM(ori_cfg->continue_fn, sync_paging_cfg->continue_fn, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[3], is_invalid[3])

        if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3])
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4])
            {
                uc_static_set_wiota_sync_paging_cfg(sync_paging_cfg);
                *is_save_static = 1;
            }
            module_queue_communication(module_get_queue(WIOTA_APP_MODULE),
                                       GATEWAY_MANAGER_MODULE,
                                       WIOTA_APP_MODULE,
                                       WIOTA_APP_SYNC_PAGING,
                                       RT_NULL);
        }
    }

    TRACE_D("set_wiota_sync_paging_cfg: dev_id %u, period %u, send_round %u, continue_fn %u",
            sync_paging_cfg->dev_id, sync_paging_cfg->detection_period, sync_paging_cfg->send_round, sync_paging_cfg->continue_fn);

    rt_free(sync_paging_cfg);

    return set_res;
}

/**
 * @brief 获取WIoTa授时配置
 *
 * @return wiota_ts_cfg_t* WIoTa授时配置信息结构体指针
 */
static wiota_ts_cfg_t *get_wiota_time_service_cfg(void)
{
    wiota_ts_cfg_t *ts_cfg = rt_malloc(sizeof(wiota_ts_cfg_t));
    RT_ASSERT(ts_cfg);
    rt_memset(ts_cfg, 0, sizeof(wiota_ts_cfg_t));

    rt_memcpy(ts_cfg, uc_static_get_wiota_ts_cfg(), sizeof(wiota_ts_cfg_t));
    TRACE_D("get_ap_ts_cfg: ts_mode %d, dev_type %d, ts_prd %d", ts_cfg->ts_mode, ts_cfg->dev_type, ts_cfg->ts_period);

    return ts_cfg;
}

/**
 * @brief 设置WIoTa授时配置
 *
 * @param ts_cfg         WIoTa授时配置信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wiota_time_service_cfg(wiota_ts_cfg_t *ts_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    unsigned char is_changed[3] = {0};
    unsigned char is_invalid[3] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    wiota_ts_cfg_t *ori_cfg = uc_static_get_wiota_ts_cfg();

    SET_CFG_PARA_NUM(ori_cfg->ts_mode, ts_cfg->ts_mode, 0xFF, UC_TS_NONE, UC_TS_SYNC_ASSISTANT, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->dev_type, ts_cfg->dev_type, 0xFF, UC_1588_DEV_SLAVE, UC_1588_DEV_MASTER, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->ts_period, ts_cfg->ts_period, 0xFF, 5, 60, is_changed[2], is_invalid[2])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2])
        {
            uc_static_set_wiota_ts_cfg(ts_cfg);
            *is_reboot = 1;
            *is_save_static = 1;
        }
    }
    TRACE_D("set_ap_ts_cfg: ts_mode %d, dev_type %d, ts_prd %d", ts_cfg->ts_mode, ts_cfg->dev_type, ts_cfg->ts_period);

    rt_free(ts_cfg);

    return set_res;
}

#ifdef WIOTA_SUBF_MODE_SUPPORT
/**
 * @brief 获取WIoTa子帧模式配置
 *
 * @return wiota_subf_mode_cfg_t* WIoTa子帧模式配置信息结构体指针
 */
static wiota_subf_mode_cfg_t *get_wiota_subframe_mode_cfg(void)
{
    wiota_subf_mode_cfg_t *subf_cfg = rt_malloc(sizeof(wiota_subf_mode_cfg_t));
    RT_ASSERT(subf_cfg);
    rt_memset(subf_cfg, 0, sizeof(wiota_subf_mode_cfg_t));

    rt_memcpy(subf_cfg, uc_static_get_wiota_subf_mode_cfg(), sizeof(wiota_subf_mode_cfg_t));
    TRACE_D("get_subf_mode_cfg: ul_subf_mode %d, block_size %d, send_round %d",
            subf_cfg->ul_subf_mode, subf_cfg->block_size, subf_cfg->dl_subf_send_round);

    return subf_cfg;
}

/**
 * @brief 设置WIoTa子帧模式配置
 *
 * @param ts_cfg         WIoTa子帧模式配置信息结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @param is_reboot      是否重启标识
 * @return char*         设置结果
 */
static char *set_wiota_subframe_mode_cfg(wiota_subf_mode_cfg_t *subf_cfg, unsigned char *is_save_static, unsigned char *is_reboot)
{
    unsigned char is_changed[3] = {0};
    unsigned char is_invalid[3] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    wiota_subf_mode_cfg_t *ori_cfg = uc_static_get_wiota_subf_mode_cfg();

    SET_CFG_PARA_NUM(ori_cfg->ul_subf_mode, subf_cfg->ul_subf_mode, 0xFF, 0, 2, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->block_size, subf_cfg->block_size, 0xFF, CFG_DL_SUBF_BLOCK_SIZE, 0xFE, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->dl_subf_send_round, subf_cfg->dl_subf_send_round, 0xFF, 1, 3, is_changed[2], is_invalid[2])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2])
        {
            uc_static_set_wiota_subf_mode_cfg(subf_cfg);
            *is_reboot = 1;
            *is_save_static = 1;
        }
    }
    TRACE_D("set_subf_mode_cfg: ul_subf_mode %d, block_size %d, send_round %d",
            subf_cfg->ul_subf_mode, subf_cfg->block_size, subf_cfg->dl_subf_send_round);

    rt_free(subf_cfg);

    return set_res;
}
#endif

/**
 * @brief 获取同步助手配置
 *
 * @return sync_cfg_t* 同步助手配置信息结构体指针
 */
static sync_cfg_t *get_sync_cfg(void)
{
    sync_cfg_t *sync_cfg = rt_malloc(sizeof(sync_cfg_t));
    RT_ASSERT(sync_cfg);
    rt_memset(sync_cfg, 0, sizeof(sync_cfg_t));

    rt_memcpy(sync_cfg, uc_static_get_sync_cfg(), sizeof(sync_cfg_t));

    TRACE_D("get_sync_cfg:");
    TRACE_D("user_def_flag %d", sync_cfg->user_def_flag);
    TRACE_D("mode %d", sync_cfg->mode);
    TRACE_D("symbol_len %d", sync_cfg->symbol_len);
    TRACE_D("bt %d", sync_cfg->bt);
    TRACE_D("mcs %d", sync_cfg->mcs);
    TRACE_D("power %d", sync_cfg->power);
    TRACE_D("freq %d", sync_cfg->freq);
    TRACE_D("wiota_log %d", sync_cfg->wiota_log);
    TRACE_D("sync_cycle %d", sync_cfg->sync_cycle);
    TRACE_D("watchdog_flag %d", sync_cfg->watchdog_flag);
    unsigned char out[128] = {0};
    int out_len = 0;
    out_len = rt_snprintf(out, 128, "whitelist [");
    for (int i = 0; i < MAX_WHITELIST_NUM; i++)
    {
        out_len += rt_snprintf(out + out_len, 128 - out_len, "%d ", sync_cfg->whitelist[i]);
    }
    rt_snprintf(out + out_len, 128 - out_len, "]");
    TRACE_D("%s", out);

    return sync_cfg;
}

/**
 * @brief 设置同步助手配置
 *
 * @param sync_cfg       同步助手配置信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_sync_cfg(sync_cfg_t *sync_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    unsigned char is_changed[10] = {0};
    unsigned char is_invalid[10] = {0};
    unsigned short default_para[MAX_WHITELIST_NUM] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    sync_cfg_t *ori_cfg = uc_static_get_sync_cfg();
    rt_memset(default_para, 0xFF, sizeof(default_para));

    sync_cfg->user_def_flag = ori_cfg->user_def_flag; // 只读
    SET_CFG_PARA_NUM(ori_cfg->mode, sync_cfg->mode, 0xFF, 0, 1, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->symbol_len, sync_cfg->symbol_len, 0xFF, 0, 3, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->bt, sync_cfg->bt, 0xFF, 0, 4, is_changed[2], is_invalid[2])
    SET_CFG_PARA_NUM(ori_cfg->mcs, sync_cfg->mcs, 0xFF, 0, 8, is_changed[3], is_invalid[3])
    SET_CFG_PARA_NUM(ori_cfg->power, sync_cfg->power, 0xFF, -16, 22, is_changed[4], is_invalid[4])
    SET_CFG_PARA_NUM(ori_cfg->freq, sync_cfg->freq, 0xFFFF, 0, 0xffff, is_changed[5], is_invalid[5])
    SET_CFG_PARA_NUM(ori_cfg->wiota_log, sync_cfg->wiota_log, 0xFF, 0, 1, is_changed[6], is_invalid[6])
    SET_CFG_PARA_NUM(ori_cfg->sync_cycle, sync_cfg->sync_cycle, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[7], is_invalid[7])
    SET_CFG_PARA_NUM(ori_cfg->watchdog_flag, sync_cfg->watchdog_flag, 0xFF, 0, 1, is_changed[8], is_invalid[8])
    SET_CFG_PARA_ARRAY(ori_cfg->whitelist, sync_cfg->whitelist, default_para, MAX_WHITELIST_NUM, is_changed[9])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] ||
        is_invalid[5] || is_invalid[6] || is_invalid[7] || is_invalid[8])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] ||
            is_changed[5] || is_changed[6] || is_changed[7] || is_changed[8] || is_changed[9])
        {
            uc_static_set_sync_cfg(sync_cfg);
            *is_reboot = 1;
            *is_save_static = 1;
        }
    }

    TRACE_D("set_sync_cfg:");
    TRACE_D("user_def_flag %d", sync_cfg->user_def_flag);
    TRACE_D("mode %d", sync_cfg->mode);
    TRACE_D("symbol_len %d", sync_cfg->symbol_len);
    TRACE_D("bt %d", sync_cfg->bt);
    TRACE_D("mcs %d", sync_cfg->mcs);
    TRACE_D("power %d", sync_cfg->power);
    TRACE_D("freq %d", sync_cfg->freq);
    TRACE_D("wiota_log %d", sync_cfg->wiota_log);
    TRACE_D("sync_cycle %d", sync_cfg->sync_cycle);
    TRACE_D("watchdog_flag %d", sync_cfg->watchdog_flag);
    unsigned char out[128] = {0};
    int out_len = 0;
    out_len = rt_snprintf(out, 128, "whitelist [");
    for (int i = 0; i < MAX_WHITELIST_NUM; i++)
    {
        out_len += rt_snprintf(out + out_len, 128 - out_len, "%d ", sync_cfg->whitelist[i]);
    }
    rt_snprintf(out + out_len, 128 - out_len, "]");
    TRACE_D("%s", out);

    rt_free(sync_cfg);

    return set_res;
}

/**
 * @brief 获取分时发送配置
 *
 * @return slot_send_cfg_t* 分时发送配置结构体指针
 */
static slot_send_cfg_t *get_slot_send_cfg(void)
{
    slot_send_cfg_t *slot_send_cfg = rt_malloc(sizeof(slot_send_cfg_t));
    RT_ASSERT(slot_send_cfg);
    rt_memset(slot_send_cfg, 0, sizeof(slot_send_cfg_t));

    rt_memcpy(slot_send_cfg, uc_static_get_slot_send_cfg(), sizeof(slot_send_cfg_t));

    TRACE_D("get_slot_send_cfg: data_transport_period %u, bc_period %d, alive_timeout %d",
            slot_send_cfg->data_transport_period, slot_send_cfg->bc_frame_send_period, slot_send_cfg->alive_timeout);
    TRACE_D("ul_len %d, dl_len %d, ul_resend_times %d, dl_resend_times %d, ul_mcs %d, dl_mcs %d",
            slot_send_cfg->ul_max_len, slot_send_cfg->dl_max_len,
            slot_send_cfg->ul_resend_times, slot_send_cfg->dl_resend_times,
            slot_send_cfg->ul_mcs, slot_send_cfg->dl_mcs);
    TRACE_D("device_access_max %d, real_data_transport_period %u", slot_send_cfg->device_access_max, slot_send_cfg->real_data_transport_period);

    return slot_send_cfg;
}

/**
 * @brief 设置分时发送配置
 *
 * @param slot_send_cfg  分时发送配置结构体指针
 * @param is_reboot      是否重启标识
 * @param is_auth_change 是否发送鉴权改变信息标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static void *set_slot_send_cfg(slot_send_cfg_t *slot_send_cfg, unsigned char *is_reboot, unsigned char *is_auth_change, unsigned char *is_save_static)
{
    unsigned char is_changed[11] = {0};
    unsigned char is_invalid[11] = {0};
    unsigned char min_value = 0;
    unsigned char gw_verity = uc_static_get_gateway_auth_cfg()->gw_verity;
    int reserved_len = 2;

    struct slot_send_res
    {
        unsigned short device_access_max;
        unsigned int real_data_transport_period;
        unsigned char set_res;
    } __attribute__((packed));

    struct slot_send_res *slot_set_res = rt_calloc(1, sizeof(struct slot_send_res));
    RT_ASSERT(slot_set_res);

    slot_send_cfg_t *ori_cfg = uc_static_get_slot_send_cfg();

    if (gw_verity)
    {
        reserved_len += 4;
    }
    slot_send_cfg->ul_max_len += reserved_len;
    slot_send_cfg->dl_max_len += reserved_len;
    if (0 != manager_time_slot_info_update(slot_send_cfg, RT_NULL, RT_NULL))
    {
        slot_set_res->set_res = 1;
        slot_set_res->real_data_transport_period = slot_send_cfg->real_data_transport_period;
        return slot_set_res;
    }

    if (slot_send_cfg->data_transport_period == 0)
        min_value = 0;
    else
        min_value = 1;

    unsigned char ul_mcs_max = slot_send_cfg->ul_mcs == UC_MCS_LEVEL_AUTO ? UC_MCS_LEVEL_AUTO : uc_static_get_max_mcs(1);
    unsigned char dl_mcs_max = slot_send_cfg->dl_mcs == UC_MCS_LEVEL_AUTO ? UC_MCS_LEVEL_AUTO : uc_static_get_max_mcs(1);

    slot_send_cfg->ul_max_len -= reserved_len;
    slot_send_cfg->dl_max_len -= reserved_len;
    SET_CFG_PARA_NUM(ori_cfg->data_transport_period, slot_send_cfg->data_transport_period, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->ul_max_len, slot_send_cfg->ul_max_len, 0xFFFF, 1, 300, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->dl_max_len, slot_send_cfg->dl_max_len, 0xFFFF, 0, 300, is_changed[2], is_invalid[2])
    SET_CFG_PARA_NUM(ori_cfg->ul_resend_times, slot_send_cfg->ul_resend_times, 0xFF, 0, 3, is_changed[3], is_invalid[3])
    SET_CFG_PARA_NUM(ori_cfg->dl_resend_times, slot_send_cfg->dl_resend_times, 0xFF, 0, 3, is_changed[4], is_invalid[4])
    SET_CFG_PARA_NUM(ori_cfg->ul_mcs, slot_send_cfg->ul_mcs, 0xFF, 0, ul_mcs_max, is_changed[5], is_invalid[5])
    SET_CFG_PARA_NUM(ori_cfg->dl_mcs, slot_send_cfg->dl_mcs, 0xFF, 0, dl_mcs_max, is_changed[6], is_invalid[6])
    SET_CFG_PARA_NUM(ori_cfg->bc_frame_send_period, slot_send_cfg->bc_frame_send_period, 0xFF, 1, CFG_FN_BROADCAST_CYCLE, is_changed[7], is_invalid[7])
    SET_CFG_PARA_NUM(ori_cfg->alive_timeout, slot_send_cfg->alive_timeout, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[8], is_invalid[8])
    SET_CFG_PARA_NUM(ori_cfg->device_access_max, slot_send_cfg->device_access_max, 0xFFFF, min_value, 0xFFFE, is_changed[9], is_invalid[9])
    SET_CFG_PARA_NUM(ori_cfg->real_data_transport_period, slot_send_cfg->real_data_transport_period, 0xFFFFFFFF, min_value, 0xFFFFFFFE, is_changed[10], is_invalid[10])

    slot_set_res->device_access_max = slot_send_cfg->device_access_max;
    slot_set_res->real_data_transport_period = slot_send_cfg->real_data_transport_period;
    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] || is_invalid[5] ||
        is_invalid[6] || is_invalid[7] || is_invalid[8] || is_invalid[9] || is_invalid[10])
    {
        slot_set_res->set_res = 1;
    }
    else
    {
        if (WIOTA_ONLINE != manager_get_wiota_state())
        {
            TRACE_E("wiota_state is offline, unable to set slot send cfg");
            slot_set_res->set_res = 1;
        }
        else
        {
            if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5] ||
                is_changed[6] || is_changed[7] || is_changed[8] || is_changed[9] || is_changed[10])
            {
                uc_static_set_slot_send_cfg(slot_send_cfg);
                if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5] ||
                    is_changed[6] || is_changed[8] || is_changed[9] || is_changed[10])
                {
                    *is_reboot = 1;
                    *is_auth_change = 1;
                }
                if (is_changed[7])
                {
                    uc_wiota_set_broadcast_fn_cycle(slot_send_cfg->bc_frame_send_period);
                }
                *is_save_static = 1;
            }
        }
    }

    TRACE_D("set_slot_send_cfg: data_transport_period %u, bc_period %d, alive_timeout %d",
            slot_send_cfg->data_transport_period, slot_send_cfg->bc_frame_send_period, slot_send_cfg->alive_timeout);
    TRACE_D("ul_len %d, dl_len %d, ul_resend_times %d, dl_resend_times %d, ul_mcs %d, dl_mcs %d",
            slot_send_cfg->ul_max_len, slot_send_cfg->dl_max_len,
            slot_send_cfg->ul_resend_times, slot_send_cfg->dl_resend_times,
            slot_send_cfg->ul_mcs, slot_send_cfg->dl_mcs);
    TRACE_D("device_access_max %d, real_data_transport_period %u", slot_send_cfg->device_access_max, slot_send_cfg->real_data_transport_period);

    rt_free(slot_send_cfg);

    return slot_set_res;
}

/**
 * @brief 获取网关基础配置
 *
 * @return gw_base_cfg_t* 网关基础配置结构体指针
 */
static gw_base_cfg_t *get_gateway_base_cfg(void)
{
    int out_len;
    char *out = rt_calloc(1, 128);
    RT_ASSERT(out);
    gw_base_cfg_t *base_cfg = rt_calloc(1, sizeof(gw_base_cfg_t));
    RT_ASSERT(base_cfg);

    rt_memcpy(base_cfg, uc_static_get_gateway_base_cfg(), sizeof(gw_base_cfg_t));
    TRACE_D("get_gateway_base_cfg: company %s, dev_id %u, hw_ver %s, soft_ver %s",
            base_cfg->company, base_cfg->dev_id, base_cfg->hardware_version, CFG_SOFTWARE_VERSION);
    out_len = rt_snprintf(out, 128, "dev_serial:");
    for (int i = 0; i < sizeof(base_cfg->dev_serial); i++)
    {
        out_len += rt_snprintf(out + out_len, 128 - out_len, " %u", base_cfg->dev_serial[i]);
    }
    TRACE_D("%s", out);
    rt_free(out);
    return base_cfg;
}

/**
 * @brief 设置网关基础配置
 *
 * @param base_cfg       网关基础配置结构体指针
 * @param is_reboot      是否如重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_gateway_base_cfg(gw_base_cfg_t *base_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    char default_para[16] = {0};
    unsigned char default_para1[16] = {0};
    unsigned char is_changed[3] = {0};
    unsigned char is_invalid[3] = {0};
    int out_len = 0;
    char *out = rt_calloc(1, 128);
    RT_ASSERT(out);

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    rt_memset(default_para1, 0xFF, sizeof(default_para));
    gw_base_cfg_t *ori_cfg = uc_static_get_gateway_base_cfg();

    if (rt_strlen(base_cfg->company) > 0)
    {
        SET_CFG_PARA_STR(ori_cfg->company, base_cfg->company, default_para, sizeof(base_cfg->company), is_changed[0], is_invalid[0])
    }
    SET_CFG_PARA_STR(ori_cfg->dev_serial, base_cfg->dev_serial, default_para1, sizeof(base_cfg->dev_serial), is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->dev_id, base_cfg->dev_id, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed[2], is_invalid[2])
    rt_memcpy(base_cfg->hardware_version, ori_cfg->hardware_version, rt_strlen(ori_cfg->hardware_version)); // 只读
    rt_memcpy(base_cfg->software_version, CFG_SOFTWARE_VERSION, rt_strlen(CFG_SOFTWARE_VERSION));           // 只读

    if (is_invalid[0] || is_invalid[1] || is_invalid[2])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2])
        {
            uc_static_set_gateway_base_cfg(base_cfg);
            *is_save_static = 1;
            *is_reboot = 1;
        }
    }

    TRACE_D("set_gateway_base_cfg: company %s, dev_id %u, hw_ver %s, soft_ver %s",
            base_cfg->company, base_cfg->dev_id, base_cfg->hardware_version, CFG_SOFTWARE_VERSION);

    out_len = rt_snprintf(out, 128, "dev_serial:");
    for (int i = 0; i < sizeof(base_cfg->dev_serial); i++)
    {
        out_len += rt_snprintf(out + out_len, 128 - out_len, " %u", base_cfg->dev_serial[i]);
    }
    TRACE_D("%s", out);

    rt_free(out);

    rt_free(base_cfg);

    return set_res;
}

/**
 * @brief 获取网关ID管理地址配置
 *
 * @return gw_id_manager_cfg_t* id管理地址配置结构体指针
 */
static gw_id_manager_cfg_t *get_id_manager_cfg(void)
{
    gw_id_manager_cfg_t *id_mng_cfg = rt_malloc(sizeof(gw_id_manager_cfg_t));
    RT_ASSERT(id_mng_cfg);
    rt_memset(id_mng_cfg, 0, sizeof(gw_id_manager_cfg_t));

    rt_memcpy(id_mng_cfg, uc_static_get_gateway_id_manager_cfg(), sizeof(gw_id_manager_cfg_t));
    TRACE_D("get_id_manager_cfg: assign_start_addr %u, assign_end_addr %u, addr_num %u",
            id_mng_cfg->assign_start_addr, id_mng_cfg->assign_end_addr, id_mng_cfg->addr_num);

    return id_mng_cfg;
}

/**
 * @brief 设置网关ID管理地址配置
 *
 * @param id_mng_cfg     id管理地址配置结构体指针
 * @param is_reboot      是否重启标识
 * @param is_auth_change 是否发送鉴权改变信息标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_id_manager_cfg(gw_id_manager_cfg_t *id_mng_cfg, unsigned char *is_reboot, unsigned char *is_auth_change, unsigned char *is_save_static)
{
    unsigned int assign_start_addr;
    unsigned int assign_end_addr;
    unsigned int addr_num;
    unsigned char is_changed[3] = {0};
    unsigned char is_invalid[3] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    gw_id_manager_cfg_t *ori_cfg = uc_static_get_gateway_id_manager_cfg();

    SET_CFG_PARA_NUM(ori_cfg->assign_start_addr, id_mng_cfg->assign_start_addr, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->assign_end_addr, id_mng_cfg->assign_end_addr, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->addr_num, id_mng_cfg->addr_num, 0xFFFFFFFF, 1, 5000, is_changed[2], is_invalid[2])
    if (is_invalid[0] || is_invalid[1] || is_invalid[2])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2])
        {
            uc_static_set_gateway_id_manager_cfg(id_mng_cfg);
            *is_reboot = 1;
            *is_auth_change = 1;
            *is_save_static = 1;
        }
    }

    TRACE_D("set_id_manager_cfg: assign_start_addr %u, assign_end_addr %u, addr_num %u",
            id_mng_cfg->assign_start_addr, id_mng_cfg->assign_end_addr, id_mng_cfg->addr_num);

    rt_free(id_mng_cfg);

    return set_res;
}

/**
 * @brief 获取网关鉴权信息
 *
 * @return gw_auth_cfg_t* 鉴权信息结构体指针
 */
static gw_auth_cfg_t *get_auth_cfg(void)
{
    gw_auth_cfg_t *auth_cfg = rt_malloc(sizeof(gw_auth_cfg_t));
    RT_ASSERT(auth_cfg);
    rt_memset(auth_cfg, 0, sizeof(gw_auth_cfg_t));

    rt_memcpy(auth_cfg, uc_static_get_gateway_auth_cfg(), sizeof(gw_auth_cfg_t));
    TRACE_D("get_auth_cfg: work_mode %d, gw_verity %d, key_type %d, key %s",
            auth_cfg->work_mode, auth_cfg->gw_verity, auth_cfg->key_type, auth_cfg->key);

    return auth_cfg;
}

/**
 * @brief 设置网关鉴权信息
 *
 * @param auth_cfg       鉴权信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_auth_change 是否发送鉴权改变信息标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_auth_cfg(gw_auth_cfg_t *auth_cfg, unsigned char *is_reboot, unsigned char *is_auth_change, unsigned char *is_save_static)
{
    char default_para[16] = {0};
    unsigned char is_changed[4] = {0};
    unsigned char is_invalid[4] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_auth_cfg_t *ori_cfg = uc_static_get_gateway_auth_cfg();

    SET_CFG_PARA_NUM(ori_cfg->work_mode, auth_cfg->work_mode, 0xFF, UC_NORMAL_MODE, UC_SYNC_RF_TEST_MODE, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->gw_verity, auth_cfg->gw_verity, 0xFF, 0, 1, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->key_type, auth_cfg->key_type, 0xFFFF, UC_KEY_TYPE1, UC_KEY_TYPE1, is_changed[2], is_invalid[2])
    SET_CFG_PARA_STR(ori_cfg->key, auth_cfg->key, default_para, sizeof(auth_cfg->key), is_changed[3], is_invalid[3])
    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3])
        {
            uc_static_set_gateway_auth_cfg(auth_cfg);
            *is_reboot = 1;
            *is_auth_change = 1;
            *is_save_static = 1;
        }
    }

    TRACE_D("set_auth_cfg: work_mode %d, gw_verity %d, key_type %d, key %s",
            auth_cfg->work_mode, auth_cfg->gw_verity, auth_cfg->key_type, auth_cfg->key);

    rt_free(auth_cfg);

    return set_res;
}

/**
 * @brief 获取所有网络配置
 *
 * @return gw_net_cfg_t* 网络配置结构体指针
 */
static gw_net_cfg_t *get_net_cfg(void)
{
    gw_net_cfg_t *net_cfg = rt_malloc(sizeof(gw_net_cfg_t));
    RT_ASSERT(net_cfg);
    rt_memset(net_cfg, 0, sizeof(gw_net_cfg_t));

    netdev_update_info();
    rt_memcpy(&net_cfg->net_policy_cfg, uc_static_get_gateway_net_policy_cfg(), sizeof(gw_net_policy_cfg_t));
    rt_memcpy(&net_cfg->net_if_cfg, uc_static_get_gateway_net_if_cfg(), sizeof(gw_net_if_cfg_t));
    rt_memcpy(&net_cfg->wifi_cfg, uc_static_get_gateway_wifi_cfg(), sizeof(gw_wifi_cfg_t));
    rt_memcpy(&net_cfg->cat1_cfg, uc_static_get_gateway_cat1_cfg(), sizeof(gw_cat1_cfg_t));

    gw_net_policy_cfg_t *net_policy_cfg = &net_cfg->net_policy_cfg;
    gw_net_if_cfg_t *if_cfg = &net_cfg->net_if_cfg;
    gw_wifi_cfg_t *wifi_cfg = &net_cfg->wifi_cfg;
    gw_cat1_cfg_t *cat1_cfg = &net_cfg->cat1_cfg;

    TRACE_D("get_net_cfg:");
    TRACE_D("net_policy_cfg:");
    TRACE_D("netdev_policy %d", net_policy_cfg->netdev_policy);
    TRACE_D("netdev_name %s\n", net_policy_cfg->netdev_name);
    TRACE_D("net_if_cfg:");
    TRACE_D("netdev_state %s", if_cfg->netdev_state);
    TRACE_D("static_ip %d", if_cfg->static_ip);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", if_cfg->mac[0], if_cfg->mac[1], if_cfg->mac[2], if_cfg->mac[3], if_cfg->mac[4], if_cfg->mac[5]);
    TRACE_D("ip_addr %s", if_cfg->ip_addr);
    TRACE_D("mask_addr %s", if_cfg->mask_addr);
    TRACE_D("gateway_addr %s", if_cfg->gateway_addr);
    TRACE_D("primary_dns %s", if_cfg->primary_dns);
    TRACE_D("secondary_dns %s\n", if_cfg->secondary_dns);
    TRACE_D("net_wifi_cfg:");
    TRACE_D("netdev_state %s", wifi_cfg->netdev_state);
    TRACE_D("static_ip %d", wifi_cfg->static_ip);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", wifi_cfg->mac[0], wifi_cfg->mac[1], wifi_cfg->mac[2], wifi_cfg->mac[3], wifi_cfg->mac[4], wifi_cfg->mac[5]);
    TRACE_D("ip_addr %s", wifi_cfg->ip_addr);
    TRACE_D("gateway_addr %s", wifi_cfg->gateway_addr);
    TRACE_D("mask_addr %s", wifi_cfg->mask_addr);
    TRACE_D("primary_dns %s", wifi_cfg->primary_dns);
    TRACE_D("secondary_dns %s", wifi_cfg->secondary_dns);
    TRACE_D("username %s ", wifi_cfg->username);
    TRACE_D("password %s\n", wifi_cfg->password);
    TRACE_D("net_cat1_cfg:");
    TRACE_D("netdev_state %s", cat1_cfg->netdev_state);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", cat1_cfg->mac[0], cat1_cfg->mac[1], cat1_cfg->mac[2], cat1_cfg->mac[3], cat1_cfg->mac[4], cat1_cfg->mac[5]);
    TRACE_D("ip_addr %s", cat1_cfg->ip_addr);
    TRACE_D("gateway_addr %s", cat1_cfg->gateway_addr);
    TRACE_D("mask_addr %s", cat1_cfg->mask_addr);
    TRACE_D("apn %s", cat1_cfg->apn);

    // 密码不可见
    if (rt_strlen(wifi_cfg->password) > 0)
    {
        rt_memset(wifi_cfg->password, 0, sizeof(wifi_cfg->password));
        rt_memset(wifi_cfg->password, '*', PASSWORD_DISPLAY_LEN);
    }

    return net_cfg;
}

/**
 * @brief 获取网口策略配置
 *
 * @return gw_net_policy_cfg_t* 网口策略配置结构体指针
 */
static gw_net_policy_cfg_t *get_net_policy_cfg(void)
{
    gw_net_policy_cfg_t *net_policy_cfg = rt_malloc(sizeof(gw_net_policy_cfg_t));
    RT_ASSERT(net_policy_cfg);
    rt_memset(net_policy_cfg, 0, sizeof(gw_net_policy_cfg_t));

    rt_memcpy(net_policy_cfg, uc_static_get_gateway_net_policy_cfg(), sizeof(gw_net_policy_cfg_t));

    TRACE_D("get_net_policy_cfg:netdev_policy %d, netdev_name %s", net_policy_cfg->netdev_policy, net_policy_cfg->netdev_name);

    return net_policy_cfg;
}

/**
 * @brief 设置网口策略配置
 *
 * @param gw_net_policy_cfg_t 网口策略配置结构体指针
 * @param is_save_static      是否保存静态数据标识
 * @return char*              设置结果
 */
static char *set_net_policy_cfg(gw_net_policy_cfg_t *net_policy_cfg, unsigned char *is_save_static)
{
    char default_para[2] = {0};
    unsigned char is_changed[2] = {0};
    unsigned char is_invalid[2] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_net_policy_cfg_t *ori_cfg = uc_static_get_gateway_net_policy_cfg();

    SET_CFG_PARA_NUM(ori_cfg->netdev_policy, net_policy_cfg->netdev_policy, 0xFFFFFFFF, 0, 1, is_changed[0], is_invalid[0])
    SET_CFG_PARA_STR(ori_cfg->netdev_name, net_policy_cfg->netdev_name, default_para, sizeof(net_policy_cfg->netdev_name), is_changed[1], is_invalid[1])

    if (is_invalid[0] || is_invalid[1])
    {
        *set_res = 1;
    }
    else
    {
        if (rt_memcmp(net_policy_cfg->netdev_name, NETDEV_INTERFACE, rt_strlen(NETDEV_INTERFACE)) != 0 &&
            (rt_memcmp(net_policy_cfg->netdev_name, NETDEV_WIFI, rt_strlen(NETDEV_WIFI)) != 0) &&
            (rt_memcmp(net_policy_cfg->netdev_name, NETDEV_CAT1, rt_strlen(NETDEV_CAT1)) != 0))
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed[0] || is_changed[1])
            {
                uc_static_set_gateway_net_policy_cfg(net_policy_cfg);
                notifice_netdev_change();
                *is_save_static = 1;
            }
        }
    }

    TRACE_D("set_net_policy_cfg: netdev_policy %d, netdev_name %s", net_policy_cfg->netdev_policy, net_policy_cfg->netdev_name);

    rt_free(net_policy_cfg);

    return set_res;
}

/**
 * @brief 获取网口配置
 *
 * @return gw_net_if_cfg_t* 网口配置结构体指针
 */
static gw_net_if_cfg_t *get_net_if_cfg(void)
{
    gw_net_if_cfg_t *if_cfg = rt_malloc(sizeof(gw_net_if_cfg_t));
    RT_ASSERT(if_cfg);
    rt_memset(if_cfg, 0, sizeof(gw_net_if_cfg_t));

    update_net_if_info();
    rt_memcpy(if_cfg, uc_static_get_gateway_net_if_cfg(), sizeof(gw_net_if_cfg_t));

    TRACE_D("get_net_if_cfg:");
    TRACE_D("netdev_state %s", if_cfg->netdev_state);
    TRACE_D("static_ip %d", if_cfg->static_ip);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", if_cfg->mac[0], if_cfg->mac[1], if_cfg->mac[2], if_cfg->mac[3], if_cfg->mac[4], if_cfg->mac[5]);
    TRACE_D("ip_addr %s", if_cfg->ip_addr);
    TRACE_D("gateway_addr %s", if_cfg->gateway_addr);
    TRACE_D("mask_addr %s", if_cfg->mask_addr);
    TRACE_D("primary_dns %s", if_cfg->primary_dns);
    TRACE_D("secondary_dns %s", if_cfg->secondary_dns);

    return if_cfg;
}

/**
 * @brief 设置网口配置
 *
 * @param if_cfg         网口配置结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_net_if_cfg(gw_net_if_cfg_t *if_cfg, unsigned char *is_save_static)
{
    char default_para[32] = {0};
    unsigned char is_changed[6] = {0};
    unsigned char is_invalid[6] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_net_if_cfg_t *ori_cfg = uc_static_get_gateway_net_if_cfg();

    rt_memcpy(if_cfg->netdev_state, ori_cfg->netdev_state, sizeof(if_cfg->netdev_state)); // 只读
    rt_memcpy(if_cfg->mac, ori_cfg->mac, sizeof(if_cfg->mac));                            // 只读
    SET_CFG_PARA_NUM(ori_cfg->static_ip, if_cfg->static_ip, 0xFFFF, 0, 1, is_changed[0], is_invalid[0])
    SET_CFG_PARA_STR(ori_cfg->ip_addr, if_cfg->ip_addr, default_para, sizeof(if_cfg->ip_addr), is_changed[1], is_invalid[1])
    SET_CFG_PARA_STR(ori_cfg->mask_addr, if_cfg->mask_addr, default_para, sizeof(if_cfg->mask_addr), is_changed[2], is_invalid[2])
    SET_CFG_PARA_STR(ori_cfg->gateway_addr, if_cfg->gateway_addr, default_para, sizeof(if_cfg->gateway_addr), is_changed[3], is_invalid[3])
    SET_CFG_PARA_STR(ori_cfg->primary_dns, if_cfg->primary_dns, default_para, sizeof(if_cfg->primary_dns), is_changed[4], is_invalid[4])
    SET_CFG_PARA_STR(ori_cfg->secondary_dns, if_cfg->secondary_dns, default_para, sizeof(if_cfg->secondary_dns), is_changed[5], is_invalid[5])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] || is_invalid[5])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5])
        {
            if (if_cfg->static_ip == 1)
            {
                uc_static_set_gateway_net_if_cfg(if_cfg);
            }
            else if (if_cfg->static_ip == 0)
            {
                ori_cfg->static_ip = if_cfg->static_ip;
            }
            *is_save_static = 1;
        }
    }

    // 当前为静态IP地址
    if (if_cfg->static_ip)
    {
        netdev_set_static_ip(NETDEV_INTERFACE, if_cfg->ip_addr, if_cfg->gateway_addr,
                             if_cfg->mask_addr, if_cfg->primary_dns, if_cfg->secondary_dns);
    }
    // 当前为动态IP地址，但是前面为静态IP地址。必须重新打开DHCP
    else
    {
        if (is_changed[0])
        {
            netdev_enable_dhcp(NETDEV_INTERFACE, RT_TRUE);
        }
    }

    TRACE_D("set_net_if_cfg: is_save_static %d", *is_save_static);
    TRACE_D("netdev_state %s", if_cfg->netdev_state);
    TRACE_D("static_ip %d", if_cfg->static_ip);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", if_cfg->mac[0], if_cfg->mac[1], if_cfg->mac[2], if_cfg->mac[3], if_cfg->mac[4], if_cfg->mac[5]);
    TRACE_D("ip_addr %s", if_cfg->ip_addr);
    TRACE_D("gateway_addr %s", if_cfg->gateway_addr);
    TRACE_D("mask_addr %s", if_cfg->mask_addr);
    TRACE_D("primary_dns %s", if_cfg->primary_dns);
    TRACE_D("secondary_dns %s", if_cfg->secondary_dns);

    rt_free(if_cfg);

    return set_res;
}

/**
 * @brief 获取WIFI配置
 *
 * @return gw_wifi_cfg_t* WIFI配置信息结构体指针
 */
static gw_wifi_cfg_t *get_wifi_cfg(void)
{
    gw_wifi_cfg_t *wifi_cfg = rt_malloc(sizeof(gw_wifi_cfg_t));
    RT_ASSERT(wifi_cfg);
    rt_memset(wifi_cfg, 0, sizeof(gw_wifi_cfg_t));

    update_wifi_info();
    rt_memcpy(wifi_cfg, uc_static_get_gateway_wifi_cfg(), sizeof(gw_wifi_cfg_t));

    TRACE_D("get_wifi_cfg:");
    TRACE_D("netdev_state %s", wifi_cfg->netdev_state);
    TRACE_D("static_ip %d", wifi_cfg->static_ip);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", wifi_cfg->mac[0], wifi_cfg->mac[1], wifi_cfg->mac[2], wifi_cfg->mac[3], wifi_cfg->mac[4], wifi_cfg->mac[5]);
    TRACE_D("ip_addr %s", wifi_cfg->ip_addr);
    TRACE_D("gateway_addr %s", wifi_cfg->gateway_addr);
    TRACE_D("mask_addr %s", wifi_cfg->mask_addr);
    TRACE_D("primary_dns %s", wifi_cfg->primary_dns);
    TRACE_D("secondary_dns %s", wifi_cfg->secondary_dns);
    TRACE_D("username %s ", wifi_cfg->username);
    TRACE_D("password %s", wifi_cfg->password);

    // 密码不可见
    if (rt_strlen(wifi_cfg->password) > 0)
    {
        rt_memset(wifi_cfg->password, 0, sizeof(wifi_cfg->password));
        rt_memset(wifi_cfg->password, '*', PASSWORD_DISPLAY_LEN);
    }

    return wifi_cfg;
}

/**
 * @brief 设置WIFI配置
 *
 * @param wifi_cfg        WIFI配置信息结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wifi_cfg(gw_wifi_cfg_t *wifi_cfg, unsigned char *is_save_static)
{
    char default_para[32] = {0};
    unsigned char is_changed[8] = {0};
    unsigned char is_invalid[8] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_wifi_cfg_t *ori_cfg = uc_static_get_gateway_wifi_cfg();

    rt_memcpy(wifi_cfg->netdev_state, ori_cfg->netdev_state, sizeof(wifi_cfg->netdev_state)); // 只读
    rt_memcpy(wifi_cfg->mac, ori_cfg->mac, sizeof(wifi_cfg->mac));                            // 只读
    SET_CFG_PARA_NUM(ori_cfg->static_ip, wifi_cfg->static_ip, 0xFFFF, 0, 1, is_changed[0], is_invalid[0])
    SET_CFG_PARA_STR(ori_cfg->ip_addr, wifi_cfg->ip_addr, default_para, sizeof(wifi_cfg->ip_addr), is_changed[1], is_invalid[1])
    SET_CFG_PARA_STR(ori_cfg->mask_addr, wifi_cfg->mask_addr, default_para, sizeof(wifi_cfg->mask_addr), is_changed[2], is_invalid[2])
    SET_CFG_PARA_STR(ori_cfg->gateway_addr, wifi_cfg->gateway_addr, default_para, sizeof(wifi_cfg->gateway_addr), is_changed[3], is_invalid[3])
    SET_CFG_PARA_STR(ori_cfg->primary_dns, wifi_cfg->primary_dns, default_para, sizeof(wifi_cfg->primary_dns), is_changed[4], is_invalid[4])
    SET_CFG_PARA_STR(ori_cfg->secondary_dns, wifi_cfg->secondary_dns, default_para, sizeof(wifi_cfg->secondary_dns), is_changed[5], is_invalid[5])
    SET_CFG_PARA_STR(ori_cfg->username, wifi_cfg->username, default_para, sizeof(wifi_cfg->username), is_changed[6], is_invalid[6])
    SET_CFG_PARA_STR(ori_cfg->password, wifi_cfg->password, default_para, sizeof(wifi_cfg->password), is_changed[7], is_invalid[7])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] || is_invalid[5] || is_invalid[6] || is_invalid[7])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5] || is_changed[6] || is_changed[7])
        {
            if (wifi_cfg->static_ip == 1)
            {
                uc_static_set_gateway_wifi_cfg(wifi_cfg);
            }
            else if (wifi_cfg->static_ip == 0)
            {
                ori_cfg->static_ip = wifi_cfg->static_ip;
            }

            rt_memcpy(ori_cfg->username, wifi_cfg->username, sizeof(wifi_cfg->username));
            rt_memcpy(ori_cfg->password, wifi_cfg->password, sizeof(wifi_cfg->password));
            *is_save_static = 1;

            if (rt_strlen(wifi_cfg->username) > 0)
            {
#ifdef RT_USING_WIFI
                if (rt_wlan_is_connected())
                {
                    rt_wlan_disconnect();
                }
                rt_wlan_connect(wifi_cfg->username, wifi_cfg->password);
#endif
            }
        }
    }

    TRACE_D("set_wifi_cfg:");
    TRACE_D("netdev_state %s", wifi_cfg->netdev_state);
    TRACE_D("static_ip %d", wifi_cfg->static_ip);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", wifi_cfg->mac[0], wifi_cfg->mac[1], wifi_cfg->mac[2], wifi_cfg->mac[3], wifi_cfg->mac[4], wifi_cfg->mac[5]);
    TRACE_D("ip_addr %s", wifi_cfg->ip_addr);
    TRACE_D("gateway_addr %s", wifi_cfg->gateway_addr);
    TRACE_D("mask_addr %s", wifi_cfg->mask_addr);
    TRACE_D("primary_dns %s", wifi_cfg->primary_dns);
    TRACE_D("secondary_dns %s", wifi_cfg->secondary_dns);
    TRACE_D("username %s ", wifi_cfg->username);
    TRACE_D("password %s", wifi_cfg->password);

    if (wifi_cfg->static_ip)
    {
        netdev_set_static_ip(NETDEV_WIFI, wifi_cfg->ip_addr, wifi_cfg->gateway_addr,
                             wifi_cfg->mask_addr, wifi_cfg->primary_dns, wifi_cfg->secondary_dns);
    }
    // 当前为动态IP地址，但是前面为静态IP地址。必须重新打开DHCP
    else
    {
        if (is_changed[0])
        {
            netdev_enable_dhcp(NETDEV_WIFI, RT_TRUE);
        }
    }

    rt_free(wifi_cfg);

    return set_res;
}

/**
 * @brief 获取cat1配置
 *
 * @return gw_cat1_cfg_t* cat1配置信息结构体指针
 */
static gw_cat1_cfg_t *get_cat1_cfg(void)
{
    gw_cat1_cfg_t *cat1_cfg = rt_malloc(sizeof(gw_cat1_cfg_t));
    RT_ASSERT(cat1_cfg);
    rt_memset(cat1_cfg, 0, sizeof(gw_cat1_cfg_t));
#ifdef PKG_USING_PPP_DEVICE
    update_cat1_info();
#endif
    rt_memcpy(cat1_cfg, uc_static_get_gateway_cat1_cfg(), sizeof(gw_cat1_cfg_t));

    TRACE_D("get_cat1_cfg:");
    TRACE_D("netdev_state %s", cat1_cfg->netdev_state);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", cat1_cfg->mac[0], cat1_cfg->mac[1], cat1_cfg->mac[2], cat1_cfg->mac[3], cat1_cfg->mac[4], cat1_cfg->mac[5]);
    TRACE_D("ip_addr %s", cat1_cfg->ip_addr);
    TRACE_D("gateway_addr %s", cat1_cfg->gateway_addr);
    TRACE_D("mask_addr %s", cat1_cfg->mask_addr);
    TRACE_D("csq:%s", cat1_cfg->csq);
    TRACE_D("ccid:%s", cat1_cfg->ccid);
    TRACE_D("cimi:%s", cat1_cfg->cimi);
    TRACE_D("gsn:%s", cat1_cfg->gsn);
    TRACE_D("apn:%s", cat1_cfg->apn);

    return cat1_cfg;
}

/**
 * @brief 设置CAT1配置
 *
 * @param cat1_cfg        CAT1配置信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_cat1_cfg(gw_cat1_cfg_t *cat1_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    char default_para[32] = {0};
    unsigned char is_changed = 0;
    unsigned char is_invalid = 0;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_cat1_cfg_t *ori_cfg = uc_static_get_gateway_cat1_cfg();

    rt_memcpy(cat1_cfg->netdev_state, ori_cfg->netdev_state, sizeof(cat1_cfg->netdev_state)); // 只读
    rt_memcpy(cat1_cfg->mac, ori_cfg->mac, sizeof(cat1_cfg->mac));                            // 只读
    rt_memcpy(cat1_cfg->ip_addr, ori_cfg->ip_addr, sizeof(cat1_cfg->ip_addr));                // 只读
    rt_memcpy(cat1_cfg->gateway_addr, ori_cfg->gateway_addr, sizeof(cat1_cfg->gateway_addr)); // 只读
    rt_memcpy(cat1_cfg->mask_addr, ori_cfg->mask_addr, sizeof(cat1_cfg->mask_addr));          // 只读
    rt_memcpy(cat1_cfg->csq, ori_cfg->csq, sizeof(cat1_cfg->csq));                            // 只读
    rt_memcpy(cat1_cfg->ccid, ori_cfg->ccid, sizeof(cat1_cfg->ccid));                         // 只读
    rt_memcpy(cat1_cfg->cimi, ori_cfg->cimi, sizeof(cat1_cfg->cimi));                         // 只读
    rt_memcpy(cat1_cfg->gsn, ori_cfg->gsn, sizeof(cat1_cfg->gsn));                            // 只读
    SET_CFG_PARA_STR(ori_cfg->apn, cat1_cfg->apn, default_para, sizeof(cat1_cfg->apn), is_changed, is_invalid)

    if (is_invalid)
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed)
        {
            uc_static_set_gateway_cat1_cfg(cat1_cfg);
            *is_save_static = 1;
            *is_reboot = 1;
        }
    }
    TRACE_D("set_cat1_cfg:");
    TRACE_D("netdev_state %s", cat1_cfg->netdev_state);
    TRACE_D("mac %x:%x:%x:%x:%x:%x", cat1_cfg->mac[0], cat1_cfg->mac[1], cat1_cfg->mac[2], cat1_cfg->mac[3], cat1_cfg->mac[4], cat1_cfg->mac[5]);
    TRACE_D("ip_addr %s", cat1_cfg->ip_addr);
    TRACE_D("gateway_addr %s", cat1_cfg->gateway_addr);
    TRACE_D("mask_addr %s", cat1_cfg->mask_addr);
    TRACE_D("csq %s", cat1_cfg->csq);
    TRACE_D("ccid %s", cat1_cfg->ccid);
    TRACE_D("cimi %s", cat1_cfg->cimi);
    TRACE_D("gsn %s", cat1_cfg->gsn);
    TRACE_D("apn %s", cat1_cfg->apn);

    rt_free(cat1_cfg);

    return set_res;
}

/**
 * @brief 获取蓝牙配置
 *
 * @return gw_bt_cfg_t* 蓝牙配置信息结构体指针
 */
static gw_bt_cfg_t *get_bt_cfg(void)
{
    gw_bt_cfg_t *bt_cfg = rt_malloc(sizeof(gw_bt_cfg_t));
    RT_ASSERT(bt_cfg);
    rt_memset(bt_cfg, 0, sizeof(gw_bt_cfg_t));

    rt_memcpy(bt_cfg, uc_static_get_gateway_bt_cfg(), sizeof(gw_bt_cfg_t));
    TRACE_D("get_bt_cfg:");
    TRACE_D("mac %s", bt_cfg->mac);

    return bt_cfg;
}

/**
 * @brief 设置蓝牙配置
 *
 * @param bt_cfg        蓝牙配置信息结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_bt_cfg(gw_bt_cfg_t *bt_cfg, unsigned char *is_save_static)
{
    char default_para[16] = {0};
    unsigned char is_changed = 0;
    unsigned char is_invalid = 0;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_bt_cfg_t *ori_cfg = uc_static_get_gateway_bt_cfg();

    SET_CFG_PARA_STR(ori_cfg->mac, bt_cfg->mac, default_para, sizeof(bt_cfg->mac), is_changed, is_invalid)

    if (is_invalid)
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed)
        {
            uc_static_set_gateway_bt_cfg(bt_cfg);
            *is_save_static = 1;
        }
    }

    TRACE_D("set_bt_cfg:");
    TRACE_D("mac %s", bt_cfg->mac);

    rt_free(bt_cfg);

    return set_res;
}

/**
 * @brief 获取MQTT服务器配置信息
 *
 * @return gw_mqtt_server_cfg_t* MQTT服务器配置信息结构体指针
 */
static gw_mqtt_server_cfg_t *get_mqtt_server_cfg(void)
{
    gw_mqtt_server_cfg_t *mqtt_cfg = rt_malloc(sizeof(gw_mqtt_server_cfg_t));
    RT_ASSERT(mqtt_cfg);
    rt_memset(mqtt_cfg, 0, sizeof(gw_mqtt_server_cfg_t));

    rt_memcpy(mqtt_cfg, uc_static_get_gateway_mqtt_cfg(), sizeof(gw_mqtt_server_cfg_t));
    TRACE_D("get_mqtt_server_cfg:");
    TRACE_D("url %s", mqtt_cfg->url);
    TRACE_D("port %d", mqtt_cfg->port);
    TRACE_D("client_id %s", mqtt_cfg->client_id);
    TRACE_D("username %s", mqtt_cfg->username);
    // TRACE_D("password %s", mqtt_cfg->password);
    TRACE_D("qos %d", mqtt_cfg->qos);

    // 密码不可见
    if (rt_strlen(mqtt_cfg->password) > 0)
    {
        rt_memset(mqtt_cfg->password, 0, sizeof(mqtt_cfg->password));
        rt_memset(mqtt_cfg->password, '*', PASSWORD_DISPLAY_LEN);
    }
    return mqtt_cfg;
}

/**
 * @brief 设置MQTT服务器配置信息
 *
 * @param mqtt_cfg       MQTT服务器配置信息结构体指针
 * @param is_reboot      是否重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_mqtt_server_cfg(gw_mqtt_server_cfg_t *mqtt_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    char default_para[32] = {0};
    unsigned char is_changed[6] = {0};
    unsigned char is_invalid[6] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_mqtt_server_cfg_t *ori_cfg = uc_static_get_gateway_mqtt_cfg();

    SET_CFG_PARA_STR(ori_cfg->url, mqtt_cfg->url, default_para, sizeof(mqtt_cfg->url), is_changed[0], is_invalid[0])
    SET_CFG_PARA_STR(ori_cfg->client_id, mqtt_cfg->client_id, default_para, sizeof(mqtt_cfg->client_id), is_changed[1], is_invalid[1])
    SET_CFG_PARA_STR(ori_cfg->username, mqtt_cfg->username, default_para, sizeof(mqtt_cfg->username), is_changed[2], is_invalid[2])
    SET_CFG_PARA_STR(ori_cfg->password, mqtt_cfg->password, default_para, sizeof(mqtt_cfg->password), is_changed[3], is_invalid[3])
    SET_CFG_PARA_NUM(ori_cfg->port, mqtt_cfg->port, 0xFFFFFFFF, 0, 0xFFFE, is_changed[4], is_invalid[4])
    SET_CFG_PARA_NUM(ori_cfg->qos, mqtt_cfg->qos, 0xFFFFFFFF, 0, 2, is_changed[5], is_invalid[5])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] || is_invalid[5])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5])
        {
            uc_static_set_gateway_mqtt_cfg(mqtt_cfg);
            *is_reboot = 1;
            *is_save_static = 1;
        }
    }

    TRACE_D("set_mqtt_server_cfg:");
    TRACE_D("url %s", mqtt_cfg->url);
    TRACE_D("port %d", mqtt_cfg->port);
    TRACE_D("client_id %s", mqtt_cfg->client_id);
    TRACE_D("username %s", mqtt_cfg->username);
    // TRACE_D("password %s", mqtt_cfg->password);
    TRACE_D("qos %d", mqtt_cfg->qos);

    rt_free(mqtt_cfg);

    return set_res;
}

/**
 * @brief 获取网关上下行数据配置
 *
 * @return gw_data_cfg_t* 上下行数据配置结构体指针
 */
static gw_data_cfg_t *get_data_cfg(void)
{
    gw_data_cfg_t *data_cfg = rt_malloc(sizeof(gw_data_cfg_t));
    RT_ASSERT(data_cfg);
    rt_memset(data_cfg, 0, sizeof(gw_data_cfg_t));

    rt_memcpy(data_cfg, uc_static_get_gateway_data_cfg(), sizeof(gw_data_cfg_t));
    TRACE_D("get_data_cfg: up_encode %d, data_flow %d, data_print %d %d",
            data_cfg->up_encode, data_cfg->ul_data_flow, data_cfg->ul_data_print, data_cfg->dl_data_print);

    return data_cfg;
}

/**
 * @brief 设置网关上下行数据配置
 *
 * @param data_cfg       上下行数据编码结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_data_cfg(gw_data_cfg_t *data_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed[4] = {0};
    unsigned char is_invalid[4] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    gw_data_cfg_t *ori_cfg = uc_static_get_gateway_data_cfg();

    SET_CFG_PARA_NUM(ori_cfg->up_encode, data_cfg->up_encode, 0xFF, UC_UP_ENCODE_NONE, UC_UP_ENCODE_HEX, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->ul_data_flow, data_cfg->ul_data_flow, 0xFF, UC_UP_DATA_FLOW_TO_NET, UC_UP_DATA_FLOW_TO_BT, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->ul_data_print, data_cfg->ul_data_print, 0xFF, 0, 1, is_changed[2], is_invalid[2])
    SET_CFG_PARA_NUM(ori_cfg->dl_data_print, data_cfg->dl_data_print, 0xFF, 0, 1, is_changed[3], is_invalid[3])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3])
        {
            uc_static_set_gateway_data_cfg(data_cfg);
            *is_save_static = 1;
        }
    }

    TRACE_D("set_data_cfg: up_encode %d, data_flow %d, data_print %d %d",
            data_cfg->up_encode, data_cfg->ul_data_flow, data_cfg->ul_data_print, data_cfg->dl_data_print);

    rt_free(data_cfg);

    return set_res;
}

/**
 * @brief 获取看门狗配置
 *
 * @return gw_wtd_cfg_t* 看门狗配置结构体指针
 */
static gw_wtd_cfg_t *get_wtd_cfg(void)
{
    gw_wtd_cfg_t *wtd_cfg = rt_malloc(sizeof(gw_wtd_cfg_t));
    RT_ASSERT(wtd_cfg);
    rt_memset(wtd_cfg, 0, sizeof(gw_wtd_cfg_t));

    rt_memcpy(wtd_cfg, uc_static_get_gateway_wtd_cfg(), sizeof(gw_wtd_cfg_t));
    TRACE_D("get_wtd_cfg: wtd_state %d", wtd_cfg->wtd_state);

    return wtd_cfg;
}

/**
 * @brief 设置看门狗配置
 *
 * @param wtd_cfg        看门狗配置结构体指针
 * @param is_reboot      是否重启标识
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_wtd_cfg(gw_wtd_cfg_t *wtd_cfg, unsigned char *is_reboot, unsigned char *is_save_static)
{
    unsigned char is_changed = 0;
    unsigned char is_invalid = 0;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    gw_wtd_cfg_t *ori_cfg = uc_static_get_gateway_wtd_cfg();

    SET_CFG_PARA_NUM(ori_cfg->wtd_state, wtd_cfg->wtd_state, 0xFF, 0, 1, is_changed, is_invalid)
    if (is_invalid)
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed)
        {
            uc_static_set_gateway_wtd_cfg(wtd_cfg);
#ifdef RT_USING_WDT
            if (wtd_cfg->wtd_state == 0)
            {
                // at32的wdt驱动不支持关闭，故重启根据静态数据判断是否启动
                *is_reboot = 1;
            }
            else
            {
                if (!watchdog_app_init())
                {
                    watchdog_app_enable();
                }
            }
#endif
            *is_save_static = 1;
        }
    }

    TRACE_D("set_wtd_cfg: wtd_state %d", wtd_cfg->wtd_state);

    rt_free(wtd_cfg);

    return set_res;
}

/**
 * @brief 获取网关FTP LOG配置
 *
 * @return gw_ftp_log_cfg_t* 网关FTP LOG配置结构体指针
 */
static gw_ftp_log_cfg_t *get_gateway_ftp_log_cfg(void)
{
    gw_ftp_log_cfg_t *log_cfg = rt_malloc(sizeof(gw_ftp_log_cfg_t));
    RT_ASSERT(log_cfg);
    rt_memset(log_cfg, 0, sizeof(gw_ftp_log_cfg_t));

    rt_memcpy(log_cfg, uc_static_get_gateway_log_cfg(), sizeof(gw_ftp_log_cfg_t));

    TRACE_D("get_gateway_ftp_log_cfg:");
    TRACE_D("ftp_log %d", log_cfg->ftp_log);
    TRACE_D("port %d", log_cfg->port);
    TRACE_D("ip_addr %s", log_cfg->ip_addr);
    TRACE_D("username %s", log_cfg->username);
    TRACE_D("password %s", log_cfg->password);
    TRACE_D("server_path %s", log_cfg->server_path);

    // 密码不可见
    if (rt_strlen(log_cfg->password) > 0)
    {
        rt_memset(log_cfg->password, 0, sizeof(log_cfg->password));
        rt_memset(log_cfg->password, '*', PASSWORD_DISPLAY_LEN);
    }

    return log_cfg;
}

/**
 * @brief 设置网关LOG配置
 *
 * @param wtd_cfg        网关LOG配置结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_gateway_ftp_log_cfg(gw_ftp_log_cfg_t *log_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed[6] = {0};
    unsigned char is_invalid[6] = {0};
    char default_para[64] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_ftp_log_cfg_t *ori_cfg = uc_static_get_gateway_log_cfg();

    SET_CFG_PARA_NUM(ori_cfg->ftp_log, log_cfg->ftp_log, 0xFF, 0, 1, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->port, log_cfg->port, 0xFFFF, 0, 0xFFFE, is_changed[1], is_invalid[1])
    SET_CFG_PARA_STR(ori_cfg->ip_addr, log_cfg->ip_addr, default_para, sizeof(log_cfg->ip_addr), is_changed[2], is_invalid[2])
    SET_CFG_PARA_STR(ori_cfg->username, log_cfg->username, default_para, sizeof(log_cfg->username), is_changed[3], is_invalid[3])
    SET_CFG_PARA_STR(ori_cfg->password, log_cfg->password, default_para, sizeof(log_cfg->password), is_changed[4], is_invalid[4])
    SET_CFG_PARA_STR(ori_cfg->server_path, log_cfg->server_path, default_para, sizeof(log_cfg->server_path), is_changed[5], is_invalid[5])

    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3] || is_invalid[4] || is_invalid[5])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3] || is_changed[4] || is_changed[5])
        {
            uc_static_set_gateway_log_cfg(log_cfg);
            zftp_app_enable(log_cfg->ftp_log);
            ulog_app_enable(log_cfg->ftp_log);
            *is_save_static = 1;
        }
    }

    TRACE_D("set_gateway_ftp_log_cfg:");
    TRACE_D("ftp_log %d", log_cfg->ftp_log);
    TRACE_D("port %d", log_cfg->port);
    TRACE_D("ip_addr %s", log_cfg->ip_addr);
    TRACE_D("username %s", log_cfg->username);
    TRACE_D("password %s", log_cfg->password);
    TRACE_D("server_path %s", log_cfg->server_path);

    rt_free(log_cfg);

    return set_res;
}

/**
 * @brief 获取LOG输出口切换切换配置
 *
 * @return gw_log_switch_cfg_t* 网关LOG配置结构体指针
 */
static gw_log_switch_cfg_t *get_log_switch_cfg(void)
{
    gw_log_switch_cfg_t *log_switch_cfg = rt_malloc(sizeof(gw_log_switch_cfg_t));
    RT_ASSERT(log_switch_cfg);
    rt_memset(log_switch_cfg, 0, sizeof(gw_log_switch_cfg_t));

    rt_memcpy(log_switch_cfg, uc_static_get_gateway_log_switch_cfg(), sizeof(gw_log_switch_cfg_t));

    TRACE_D("get_log_switch_cfg:log_uart %s, ap_log_output %d", log_switch_cfg->log_uart, log_switch_cfg->ap_log_output);

    return log_switch_cfg;
}

/**
 * @brief LOG输出口切换切换配置
 *
 * @param log_switch_cfg log口切换配置结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_log_switch_cfg(gw_log_switch_cfg_t *log_switch_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed[2] = {0};
    unsigned char is_invalid[2] = {0};
    char default_para[8] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    gw_log_switch_cfg_t *ori_cfg = uc_static_get_gateway_log_switch_cfg();

    if (0 != rt_memcmp(RT_CONSOLE_DEVICE_NAME, log_switch_cfg->log_uart, rt_strlen(RT_CONSOLE_DEVICE_NAME)) &&
        0 != rt_memcmp(USER_COM_485_NAME, log_switch_cfg->log_uart, rt_strlen(USER_COM_485_NAME)) &&
        0 != rt_memcmp(USER_COM_BT_NAME, log_switch_cfg->log_uart, rt_strlen(USER_COM_BT_NAME)))
    {
        *set_res = 1;
        TRACE_D("set_log_switch_cfg:log_uart %s is invalid, only support %s , %s and %s",
                log_switch_cfg->log_uart, RT_CONSOLE_DEVICE_NAME, USER_COM_485_NAME, USER_COM_BT_NAME);
    }
    else
    {
        SET_CFG_PARA_STR(ori_cfg->log_uart, log_switch_cfg->log_uart, default_para, sizeof(log_switch_cfg->log_uart), is_changed[0], is_invalid[0])
        SET_CFG_PARA_NUM(ori_cfg->ap_log_output, log_switch_cfg->ap_log_output, 0xFF, 0, 1, is_changed[1], is_invalid[1])
        if (is_invalid[0] || is_invalid[1])
        {
            *set_res = 1;
        }
        else
        {
            if (is_changed[0] || is_changed[1])
            {
                if (is_changed[0])
                {
                    rt_console_switch_device(log_switch_cfg->log_uart);
                }
                uc_static_set_gateway_log_switch_cfg(log_switch_cfg);
                *is_save_static = 1;
            }
        }
        TRACE_D("set_log_switch_cfg:log_uart %s, ap_log_output %d", log_switch_cfg->log_uart, log_switch_cfg->ap_log_output);
    }

    rt_free(log_switch_cfg);

    return set_res;
}

/**
 * @brief 获取UART_485配置
 *
 * @return gw_uart_485_cfg_t* 网关uart_485配置结构体指针
 */
static gw_uart_485_cfg_t *get_uart_485_cfg(void)
{
    gw_uart_485_cfg_t *uart_485_cfg = rt_malloc(sizeof(gw_uart_485_cfg_t));
    RT_ASSERT(uart_485_cfg);
    rt_memset(uart_485_cfg, 0, sizeof(gw_uart_485_cfg_t));

    rt_memcpy(uart_485_cfg, uc_static_get_gateway_uart_485_cfg(), sizeof(gw_uart_485_cfg_t));

    TRACE_D("get_uart_485_cfg:baud %d", uart_485_cfg->baud_rate);

    return uart_485_cfg;
}

/**
 * @brief uart_485配置
 *
 * @param uart_485_cfg uart_485配置结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_uart_485_cfg(gw_uart_485_cfg_t *uart_485_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed = 0;
    unsigned char is_invalid = 0;

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    gw_uart_485_cfg_t *ori_cfg = uc_static_get_gateway_uart_485_cfg();

    SET_CFG_PARA_NUM(ori_cfg->baud_rate, uart_485_cfg->baud_rate, 0xFFFFFFFF, 1, 0xFFFFFFFE, is_changed, is_invalid)
    if (is_changed)
    {
        uc_static_set_gateway_uart_485_cfg(uart_485_cfg);
        serial_app_485_baud_rate_set(uart_485_cfg->baud_rate);
        *is_save_static = 1;
    }

    if (is_invalid)
    {
        *set_res = 1;
    }

    TRACE_D("set_uart_485_cfg:baud %d", uart_485_cfg->baud_rate);

    rt_free(uart_485_cfg);

    return set_res;
}

/**
 * @brief 获取网关定时配置
 *
 * @return gw_timed_cfg_t* 网关定时配置结构体指针
 */
static gw_timed_cfg_t *get_timed_cfg(void)
{
    gw_timed_cfg_t *timed_cfg = rt_malloc(sizeof(gw_timed_cfg_t));
    RT_ASSERT(timed_cfg);
    rt_memset(timed_cfg, 0, sizeof(gw_timed_cfg_t));

    rt_memcpy(timed_cfg, uc_static_get_gateway_timed_cfg(), sizeof(gw_timed_cfg_t));

    TRACE_D("get_timed_cfg:time %u, abnormal_time %u, rc_time %u, rc_rto %d",
            timed_cfg->time, timed_cfg->abnormal_time, timed_cfg->roll_call_time, timed_cfg->rc_rto);

    return timed_cfg;
}

/**
 * @brief 设置网关定时配置
 *
 * @param timed_cfg      网关定时配置结构体指针
 * @param is_save_static 是否保存静态数据标识
 * @return char*         设置结果
 */
static char *set_timed_cfg(gw_timed_cfg_t *timed_cfg, unsigned char *is_save_static)
{
    unsigned char is_changed[4] = {0};
    unsigned char is_invalid[4] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    gw_timed_cfg_t *ori_cfg = uc_static_get_gateway_timed_cfg();

    SET_CFG_PARA_NUM(ori_cfg->time, timed_cfg->time, 0xFFFFFFFF, 0, 24, is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->abnormal_time, timed_cfg->abnormal_time, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->roll_call_time, timed_cfg->roll_call_time, 0xFFFFFFFF, 0, 0xFFFFFFFE, is_changed[2], is_invalid[2])
    SET_CFG_PARA_NUM(ori_cfg->rc_rto, timed_cfg->rc_rto, 0xFFFFFFFF, 0, 1, is_changed[3], is_invalid[3])

    if (timed_cfg->roll_call_time == 0 && timed_cfg->rc_rto == 1) // rc_rto只有在roll_call_time不为0时才有效
    {
        timed_cfg->rc_rto = 0;
    }
    if (is_invalid[0] || is_invalid[1] || is_invalid[2] || is_invalid[3])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2] || is_changed[3])
        {
            uc_static_set_gateway_timed_cfg(timed_cfg);
            if (is_changed[0])
            {
                extern int gateway_reboot_time_set(unsigned int hour);
                gateway_reboot_time_set(timed_cfg->time);
            }
            if (is_changed[2])
            {
                manager_roll_call_timer_reset();
            }
            *is_save_static = 1;
        }
    }

    TRACE_D("set_timed_cfg:time %u, abnormal_time %u, rc_time %u, rc_rto %d",
            timed_cfg->time, timed_cfg->abnormal_time, timed_cfg->roll_call_time, timed_cfg->rc_rto);

    rt_free(timed_cfg);

    return set_res;
}

/**
 * @brief 重置静态数据
 *
 * @param is_reboot 是否重启标识
 * @return char*    设置结果
 */
static char *static_data_reset(unsigned char *is_reboot)
{
    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    uc_static_data_reset();
    uc_boot_cfg_reset();

    *is_reboot = 1;

    return set_res;
}

/**
 * @brief 网关重启
 *
 * @param is_reboot 是否重启标识
 * @return char*    设置结果
 */
static char *gateway_reboot(unsigned char *is_reboot)
{
    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    *is_reboot = 1;

    return set_res;
}

/**
 * @brief 获取uboot配置
 *
 * @return uboot_cfg_t* uboot配置
 */
static uboot_cfg_t *get_uboot_cfg(void)
{
    uboot_cfg_t *uboot_cfg = rt_malloc(sizeof(uboot_cfg_t));
    RT_ASSERT(uboot_cfg);
    rt_memset(uboot_cfg, 0, sizeof(uboot_cfg_t));

    rt_memcpy(uboot_cfg, uc_get_uboot_cfg(), sizeof(uboot_cfg_t));

    TRACE_D("get_uboot_cfg ymode_uart %s, time %d, uboot_mode %d, ota_state %d, ota_size %d",
            uboot_cfg->ymode_uart, uboot_cfg->ymode_wait_time, uboot_cfg->uboot_mode, uboot_cfg->ota_state, uboot_cfg->ota_size);

    return uboot_cfg;
}

/**
 * @brief 设置uboot配置
 *
 * @param uboot_cfg uboot配置
 * @param is_reboot 是否重启标识
 * @return char*    设置结果
 */
static char *set_uboot_cfg(uboot_cfg_t *uboot_cfg, unsigned char *is_reboot)
{
    unsigned char is_changed[3] = {0};
    unsigned char is_invalid[3] = {0};
    unsigned char default_para[8] = {0};

    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    rt_memset(default_para, 0xFF, sizeof(default_para));
    uboot_cfg_t *ori_cfg = uc_get_uboot_cfg();

    uboot_cfg->ota_state = ori_cfg->ota_state; // 只读
    uboot_cfg->ota_size = ori_cfg->ota_size;   // 只读
    SET_CFG_PARA_STR(ori_cfg->ymode_uart, uboot_cfg->ymode_uart, default_para, sizeof(uboot_cfg->ymode_uart), is_changed[0], is_invalid[0])
    SET_CFG_PARA_NUM(ori_cfg->ymode_wait_time, uboot_cfg->ymode_wait_time, 0xFF, 0, 0xFE, is_changed[1], is_invalid[1])
    SET_CFG_PARA_NUM(ori_cfg->uboot_mode, uboot_cfg->uboot_mode, 0xFF, UC_YMODEM_DOWNLOAD, UC_YMODEM_DOWNLOAD, is_changed[2], is_invalid[2])
    if (is_invalid[0] || is_invalid[1] || is_invalid[2])
    {
        *set_res = 1;
    }
    else
    {
        if (is_changed[0] || is_changed[1] || is_changed[2])
        {
            uc_set_uboot_cfg(uboot_cfg);
            uc_boot_cfg_save();
            if (is_changed[2])
            {
                *is_reboot = 1;
            }
        }
    }

    TRACE_D("set_uboot_cfg ymode_uart %s, time %d, uboot_mode %d, ota_state %d, ota_size %d",
            uboot_cfg->ymode_uart, uboot_cfg->ymode_wait_time, uboot_cfg->uboot_mode, uboot_cfg->ota_state, uboot_cfg->ota_size);

    rt_free(uboot_cfg);

    return set_res;
}

/**
 * @brief 获取参数立即生效标识
 *
 */
static void *get_immediate_effective_cfg(void)
{
    unsigned int *flag = rt_malloc(sizeof(int));
    RT_ASSERT(flag);
    rt_memset(flag, 0, sizeof(int));

    flag[0] = g_immedicate_effect_flag;

    TRACE_D("get_immediate_effective_cfg %d", *flag);

    return flag;
}

/**
 * @brief 设置参数立即生效标识
 *
 * @param flag   立即生效标识
 * @return char*    设置结果
 */
static char *set_immediate_effective_cfg(unsigned int *flag)
{
    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    g_immedicate_effect_flag = flag[0];

    TRACE_D("set_immediate_effective_cfg %d", *flag);

    rt_free(flag);

    return set_res;
}

/**
 * @brief 执行MSH命令
 *
 * @param cmd    MSH命令
 * @return char* 执行结果
 */
static char *msh_cmd_exec(char *cmd)
{
    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0xff;

    if (rt_strlen(cmd) > 0)
    {
        rt_kprintf("msh /> %s\n", cmd);
        *set_res = msh_exec(cmd, rt_strlen(cmd));
    }
    // TRACE_D("msh_cmd_exec %s, res %d", cmd, *set_res);

    rt_free(cmd);

    return set_res;
}

/**
 * @brief 获取工厂测试结果
 *
 */
static void *get_factory_test_result(void)
{
    factory_test_t *ft_res = rt_malloc(sizeof(factory_test_t) * FACTORY_MODE);
    RT_ASSERT(ft_res);
    rt_memset(ft_res, 0, sizeof(sizeof(factory_test_t) * FACTORY_MODE));

    rt_memcpy(ft_res, factory_get_data(), sizeof(factory_test_t) * FACTORY_MODE);

    TRACE_D("get_factory_test_result");

    return ft_res;
}

/**
 * @brief 获取在线设备列表
 *
 */
static void *get_online_device_list(void)
{
    manager_list_t *auth_list = get_auth_list();
    manager_list_t *cur_list = RT_NULL;
    manager_list_t *next_node = RT_NULL;
    gateway_auth_node_t *auth_node = RT_NULL;

    online_device_list_t *online_device = rt_malloc(sizeof(online_device_list_t));
    RT_ASSERT(online_device);

    online_device->online_number = 0;
    for (int i = 0; i < AUTH_LIST_LEN; i++)
    {
        cur_list = &auth_list[i];
        next_node = cur_list->next;
        while (next_node != cur_list)
        {
            auth_node = (gateway_auth_node_t *)next_node->data;
            if (auth_node->is_online != 0)
            {
                online_device->online_number += 1;
                online_device = rt_realloc(online_device, sizeof(online_device_list_t) + online_device->online_number * sizeof(unsigned int));
                RT_ASSERT(online_device);
                online_device->dev_id[online_device->online_number - 1] = auth_node->dev_id;
            }

            next_node = next_node->next;
        }
    }

    TRACE_D("get_online_device_list");

    return online_device;
}

/**
 * @brief 获取网关时间
 *
 */
static void *get_gateway_time(void)
{
    time_t *timestamp = rt_calloc(1, sizeof(time_t));

    get_timestamp(timestamp);

    TRACE_D("get_gateway_time");

    return timestamp;
}

static void gateway_default_debug(void)
{
    gw_log_switch_cfg_t *log_cfg = uc_static_get_gateway_log_switch_cfg();

    if (0 == rt_memcmp(RT_CONSOLE_DEVICE_NAME, log_cfg->log_uart, rt_strlen(RT_CONSOLE_DEVICE_NAME)) ||
        0 == rt_memcmp(USER_COM_485_NAME, log_cfg->log_uart, rt_strlen(USER_COM_485_NAME)) ||
        0 == rt_memcmp(USER_COM_BT_NAME, log_cfg->log_uart, rt_strlen(USER_COM_BT_NAME)))
    {
        rt_console_switch_device(log_cfg->log_uart);
    }
    else
    {
        rt_console_switch_device(RT_CONSOLE_DEVICE_NAME);
        TRACE_E("log_uart %s is invalid, only support %s , %s and %s, recover to default log_uart %s",
                log_cfg->log_uart, RT_CONSOLE_DEVICE_NAME, USER_COM_485_NAME, USER_COM_BT_NAME, RT_CONSOLE_DEVICE_NAME);
    }
}

/**
 * @brief 获取鉴权列表信息
 *
 * @return void*   鉴权列表信息
 */
static void *get_gateway_auth_list(void)
{
    manager_list_t *auth_list = get_auth_list();
    manager_list_t *cur_list = RT_NULL;
    manager_list_t *next_node = RT_NULL;
    gateway_auth_node_t *auth_node = RT_NULL;
    manager_address_t *reserve_addr = RT_NULL;
    int num = 0;

    gw_auth_list_info_t *auth_list_info = rt_malloc(sizeof(gw_auth_list_info_t));
    RT_ASSERT(auth_list_info);
    rt_memset(auth_list_info, 0, sizeof(gw_auth_list_info_t));

    auth_list_info->auth_total_num = manager_get_reallocated_num();
    if (auth_list_info->auth_total_num > 0)
    {
        auth_list_info->auth_info = rt_malloc(sizeof(auth_info_t) * auth_list_info->auth_total_num);
        RT_ASSERT(auth_list_info->auth_info);

        for (int i = 0; i < AUTH_LIST_LEN; i++)
        {
            cur_list = &auth_list[i];
            next_node = cur_list->next;
            while (next_node != cur_list)
            {
                auth_node = (gateway_auth_node_t *)next_node->data;
                if (auth_node->is_online)
                {
                    reserve_addr = manager_query_reserve_addr_by_dev_id(auth_node->dev_id);

                    if (num < auth_list_info->auth_total_num)
                    {
                        rt_snprintf(auth_list_info->auth_info[num].dev_id_key,
                                    sizeof(auth_list_info->auth_info[num].dev_id_key),
                                    "%d",
                                    auth_node->dev_id);
                        rt_snprintf(auth_list_info->auth_info[num].info_str,
                                    sizeof(auth_list_info->auth_info[num].info_str),
                                    "0x%x, pos %d %d, ts %d %d",
                                    (reserve_addr->wiota_id | (1 << 31)),
                                    reserve_addr->burst_idx,
                                    reserve_addr->slot_idx,
                                    manager_get_ul_time_slot_fn_pos(reserve_addr->time_slot_fn),
                                    reserve_addr->time_slot_fn);
                        num++;
                    }
                    else
                    {
                        TRACE_E("auth_total_num is error, num %d %d", auth_list_info->auth_total_num, num);
                    }
                }

                next_node = next_node->next;
            }
        }
    }
    TRACE_D("get_gateway_auth_list, num %d", auth_list_info->auth_total_num);

    return auth_list_info;
}

/**
 * @brief 处理网关扫频请求
 *
 * @param scan_req 扫频请求
 * @return void*   扫频响应
 */
void *gateway_scan_freq_req(gw_scan_freq_req_t *scan_req)
{
    uc_scan_recv_t scan_recv = {0};
    uc_scan_freq_t *freq_info = NULL;
    unsigned int timeout = 0;
    const char *result[2] = {"fail", "suc"};
    unsigned char freq_list[UC_FREQ_LIST_MAX_NUM] = {0};
    unsigned char *freq_list_p = RT_NULL;
    int freq_num = 0;
    int is_suc = 0;
    int is_finsh = 0;

    gw_scan_freq_resp_t *scan_resp = rt_malloc(sizeof(gw_scan_freq_resp_t));
    RT_ASSERT(scan_resp);
    rt_memset(scan_resp, 0, sizeof(gw_scan_freq_resp_t));

    // 扫网关频点列表
    if (scan_req->freq_num == 0 && scan_req->freq_list == RT_NULL)
    {
        // 从静态数据中获取频点列表
        freq_num = wiota_get_freq_list(freq_list);
        freq_list_p = freq_list;
        timeout = freq_num * 2000;
    }
    else if (scan_req->freq_num < 201)
    {
        // 自定义频点列表
        freq_list_p = scan_req->freq_list;
        freq_num = scan_req->freq_num;
        timeout = freq_num * 2000;
    }
    else
    {
        // 总计201个频点，表示全扫，全扫freq_list_p传RT_NULL，freq_num传0即可
        timeout = 201 * 2000;
    }

    manager_set_scan_freq_state(1);

    if (WIOTA_ONLINE == manager_get_wiota_state())
    {
        if (UC_OP_SUCC == uc_wiota_scan_freq(freq_list_p, freq_num, 0, timeout, RT_NULL, &scan_recv))
        {
            if (UC_OP_SUCC == scan_recv.result && RT_NULL != scan_recv.freq_info)
            {
                is_suc = 1;

                rt_memcpy(scan_resp->result, result[is_suc], rt_strlen(result[is_suc]));

                scan_resp->scan_res = rt_malloc(scan_recv.freq_num * sizeof(scan_result_t));
                RT_ASSERT(scan_resp->scan_res);
                rt_memset(scan_resp->scan_res, 0, scan_recv.freq_num * sizeof(scan_result_t));

                freq_info = scan_recv.freq_info;
                for (int i = 0; i < scan_recv.freq_num; i++)
                {
                    rt_snprintf(scan_resp->scan_res[i].freq_key,
                                sizeof(scan_resp->scan_res[i].freq_key),
                                "%d", freq_info[i].freq_idx);
                    rt_snprintf(scan_resp->scan_res[i].info_str,
                                sizeof(scan_resp->scan_res[i].info_str),
                                "rssi %d, snr %d, is_synced %d", freq_info[i].rssi, freq_info[i].snr, freq_info[i].is_synced);
                    scan_resp->scan_res_num++;
                }
                rt_free(scan_recv.freq_info);
            }
        }
    }
    else
    {
        TRACE_W("wiota is offline, not support scan freq");
        g_is_scan_stop = 1; // 强制停止扫频
    }

    if (!is_suc)
    {
        rt_memcpy(scan_resp->result, result[is_suc], rt_strlen(result[is_suc]));
        scan_resp->scan_res_num = 0;
    }

    scan_req->scaned_times += 1;
    scan_resp->scaned_times = scan_req->scaned_times;

    TRACE_I("scaned_times %d/%d", scan_req->scaned_times, scan_req->scan_times);

    if (scan_req->scaned_times < scan_req->scan_times)
    {
        // 重新塞进队列继续扫频
        if (g_is_scan_stop == 0)
        {
            if (0 != module_queue_communication(get_gateway_manager_queue(),
                                                NET_APP_MODULE,
                                                GATEWAY_MANAGER_MODULE,
                                                GATEWAY_SCAN_FREQ_REQ,
                                                scan_req))
            {
                is_finsh = 1;
            }
        }
        else
        {
            is_finsh = 1;
        }
    }
    else
    {
        is_finsh = 1;
    }

    if (is_finsh)
    {
        if (scan_req->freq_list)
        {
            rt_free(scan_req->freq_list);
        }
        rt_free(scan_req);
        g_is_scan_stop = 0;
        manager_set_scan_freq_state(0);
        TRACE_I("scan_freq_req finish");
    }

    return scan_resp;
}

/**
 * @brief 停止网关扫频
 *
 * @return void* 命令执行结果
 */
static void *gateway_scan_freq_stop(void)
{
    char *set_res = rt_malloc(sizeof(char));
    RT_ASSERT(set_res);
    *set_res = 0;

    if (manager_get_scan_freq_state())
    {
        g_is_scan_stop = 1;
        TRACE_D("gateway_scan_freq_stop");
    }
    else
    {
        TRACE_W("scan_freq is not running");
    }

    return set_res;
}

/**
 * @brief 获取同步助手动态信息
 *
 * @return void* 动态信息
 */
static void *get_sync_dynamics_info(void)
{
    return wiota_get_sync_dynamics_info();
}

/**
 * @brief 处理下行链路消息
 *
 * @param from_module 来自哪个线程的命令，net、web、serial、serial debug或BT
 * @param cmd         命令类型
 * @param data        数据
 */
void manager_handle_downlink_msg(int from_module, int cmd, void *data)
{
    void *resp_data = RT_NULL;
    unsigned char is_reboot = 0;
    unsigned char is_force_reboot = 0;
    unsigned char is_auth_change = 0;
    unsigned char is_save_static = 0;

    // TRACE_I("mng dl recv from module %d, cmd %d", from_module, cmd);

    switch (cmd)
    {
    case SERIAL_INIT_FINISH:
        TRACE_I("mng SERIAL_FINISH");
        gateway_default_debug();
        break;

    case WIOTA_SEND_DATA:
        // dl: down link module
        TRACE_I("mng dm %d WIOTA_SEND_DATA", from_module);
        manager_handle_dl_user_data_msg(from_module, (net_dl_userdata_t *)data, 0, 0);
        break;

    case OTA_UPGRADE_REQUEST:
        // dl: down link module
        TRACE_I("mng dm %d OTA_UPGRADE_REQUEST", from_module);
        manager_handle_ota_upgrade_req_msg(from_module, (ota_upgrade_req_t *)data);
        break;

    case OTA_UPGRADE_RESPONSE:
        // dl: down link module
        TRACE_I("mng dm %d OTA_UPGRADE_RESPONSE", from_module);
        manager_handle_ota_upgrade_res_msg(from_module, (ota_upgrade_res_t *)data);
        break;

    case OTA_UPGRADE_DATA_SENDING:
        // dl: down link module
        TRACE_I("mng dm %d OTA_UPGRADE_DATA_SENDING", from_module);
        manager_handle_ota_upgrade_data_sending_msg();
        break;

    case OTA_UPGRADE_COMPLETE:
        // dl: down link module
        TRACE_I("mng dm %d OTA_UPGRADE_COMPLETE", from_module);
        manager_handle_ota_upgrade_complete_msg();
        break;

    case WIOAT_VERSION_GET:
        TRACE_I("mng dm %d WIOAT_VERSION_GET", from_module);
        resp_data = (void *)get_wiota_version();
        break;

    case WIOTA_SYS_CFG_GET:
        TRACE_I("mng dm %d WIOTA_SYS_CFG_GET", from_module);
        resp_data = (void *)get_wiota_sys_cfg();
        break;
    case WIOTA_SYS_CFG_SET:
        TRACE_I("mng dm %d WIOTA_SYS_CFG_SET", from_module);
        resp_data = (void *)set_wiota_sys_cfg((wiota_sys_cfg_t *)data, &is_reboot, &is_save_static);
        break;

    case WIOTA_ACT_CFG_GET:
        TRACE_I("mng dm %d WIOTA_ACT_CFG_GET", from_module);
        resp_data = (void *)get_wiota_act_cfg();
        break;
    case WIOTA_ACT_CFG_SET:
        TRACE_I("mng dm %d WIOTA_ACT_CFG_SET", from_module);
        resp_data = (void *)set_wiota_act_cfg((wiota_act_cfg_t *)data, &is_save_static);
        break;

    case WIOTA_FREQ_CFG_GET:
        TRACE_I("mng dm %d WIOTA_FREQ_CFG_GET", from_module);
        resp_data = (void *)get_wiota_freq_cfg();
        break;
    case WIOTA_FREQ_CFG_SET:
        TRACE_I("mng dm %d WIOTA_FREQ_CFG_SET", from_module);
        resp_data = (void *)set_wiota_freq_cfg((wiota_freq_cfg_t *)data, &is_reboot, &is_auth_change, &is_save_static);
        break;

    case WIOTA_POWER_CFG_GET:
        TRACE_I("mng dm %d WIOTA_POWER_CFG_GET", from_module);
        resp_data = (void *)get_wiota_power_cfg();
        break;
    case WIOTA_POWER_CFG_SET:
        TRACE_I("mng dm %d WIOTA_POWER_CFG_SET", from_module);
        resp_data = (void *)set_wiota_power_cfg((wiota_power_cfg_t *)data, &is_save_static);
        break;

    case WIOTA_RATE_CFG_GET:
        TRACE_I("mng dm %d WIOTA_RATE_CFG_GET", from_module);
        resp_data = (void *)get_wiota_rate_cfg();
        break;
    case WIOTA_RATE_CFG_SET:
        TRACE_I("mng dm %d WIOTA_RATE_CFG_SET", from_module);
        resp_data = (void *)set_wiota_rate_cfg((wiota_rate_cfg_t *)data, &is_save_static);
        break;

    case WIOTA_PAGING_TX_CFG_GET:
        TRACE_I("mng dm %d WIOTA_PAGING_TX_CFG_GET", from_module);
        resp_data = (void *)get_wiota_paging_tx_cfg();
        break;
    case WIOTA_PAGING_TX_CFG_SET:
        TRACE_I("mng dm %d WIOTA_PAGING_TX_CFG_SET", from_module);
        resp_data = (void *)set_wiota_paging_tx_cfg(data, from_module, &is_save_static);
        break;

    case WIOTA_SYNC_PAGING_CFG_GET:
        TRACE_I("mng dm %d WIOTA_SYNC_PAGING_CFG_GET", from_module);
        resp_data = (void *)get_wiota_sync_paging_cfg();
        break;
    case WIOTA_SYNC_PAGING_CFG_SET:
        TRACE_I("mng dm %d WIOTA_SYNC_PAGING_CFG_SET", from_module);
        resp_data = (void *)set_wiota_sync_paging_cfg((wiota_sync_paging_cfg_t *)data, &is_save_static);
        break;

    case WIOTA_TS_CFG_GET:
        TRACE_I("mng dm %d WIOTA_TS_CFG_GET", from_module);
        resp_data = (void *)get_wiota_time_service_cfg();
        break;
    case WIOTA_TS_CFG_SET:
        TRACE_I("mng dm %d WIOTA_TS_CFG_SET", from_module);
        resp_data = (void *)set_wiota_time_service_cfg((wiota_ts_cfg_t *)data, &is_reboot, &is_save_static);
        break;

#ifdef WIOTA_SUBF_MODE_SUPPORT
    case WIOTA_SUBF_MODE_CFG_GET:
        resp_data = (void *)get_wiota_subframe_mode_cfg();
        break;
    case WIOTA_SUBF_MODE_CFG_SET:
        resp_data = (void *)set_wiota_subframe_mode_cfg((wiota_subf_mode_cfg_t *)data, &is_save_static, &is_reboot);
        break;
#endif

    case SLOT_SEND_CFG_GET:
        TRACE_I("mng dm %d SLOT_SEND_CFG_GET", from_module);
        resp_data = (void *)get_slot_send_cfg();
        break;
    case SLOT_SEND_CFG_SET:
        TRACE_I("mng dm %d SLOT_SEND_CFG_SET", from_module);
        resp_data = (void *)set_slot_send_cfg((slot_send_cfg_t *)data, &is_reboot, &is_auth_change, &is_save_static);
        break;

    case GATEWAY_BASE_CFG_GET:
        TRACE_I("mng dm %d GATEWAY_BASE_CFG_GET", from_module);
        resp_data = (void *)get_gateway_base_cfg();
        break;
    case GATEWAY_BASE_CFG_SET:
        TRACE_I("mng dm %d GATEWAY_BASE_CFG_SET", from_module);
        resp_data = (void *)set_gateway_base_cfg((gw_base_cfg_t *)data, &is_reboot, &is_save_static);
        break;

    case ID_MANAGER_CFG_GET:
        TRACE_I("mng dm %d ID_MANAGER_CFG_GET", from_module);
        resp_data = (void *)get_id_manager_cfg();
        break;
    case ID_MANAGER_CFG_SET:
        TRACE_I("mng dm %d ID_MANAGER_CFG_SET", from_module);
        resp_data = (void *)set_id_manager_cfg((gw_id_manager_cfg_t *)data, &is_reboot, &is_auth_change, &is_save_static);
        break;

    case AUTH_CFG_GET:
        TRACE_I("mng dm %d AUTH_CFG_GET", from_module);
        resp_data = (void *)get_auth_cfg();
        break;
    case AUTH_CFG_SET:
        TRACE_I("mng dm %d AUTH_CFG_SET", from_module);
        resp_data = (void *)set_auth_cfg((gw_auth_cfg_t *)data, &is_reboot, &is_auth_change, &is_save_static);
        break;

    case NET_CFG_GET:
        TRACE_I("mng dm %d NET_CFG_GET", from_module);
        resp_data = (void *)get_net_cfg();
        break;

    case NET_POLICY_CFG_GET:
        TRACE_I("mng dm %d NET_POLICY_CFG_GET", from_module);
        resp_data = (void *)get_net_policy_cfg();
        break;
    case NET_POLICY_CFG_SET:
        TRACE_I("mng dm %d NET_POLICY_CFG_SET", from_module);
        resp_data = (void *)set_net_policy_cfg((gw_net_policy_cfg_t *)data, &is_save_static);
        break;

    case NET_IF_CFG_GET:
        TRACE_I("mng dm %d NET_IF_CFG_GET", from_module);
        resp_data = (void *)get_net_if_cfg();
        break;
    case NET_IF_CFG_SET:
        TRACE_I("mng dm %d NET_IF_CFG_SET", from_module);
        resp_data = (void *)set_net_if_cfg((gw_net_if_cfg_t *)data, &is_save_static);
        break;

    case WIFI_CFG_GET:
        TRACE_I("mng dm %d WIFI_CFG_GET", from_module);
        resp_data = (void *)get_wifi_cfg();
        break;
    case WIFI_CFG_SET:
        TRACE_I("mng dm %d WIFI_CFG_SET", from_module);
        resp_data = (void *)set_wifi_cfg((gw_wifi_cfg_t *)data, &is_save_static);
        break;

    case CAT1_CFG_GET:
        TRACE_I("mng dm %d CAT1_CFG_GET", from_module);
        resp_data = (void *)get_cat1_cfg();
        break;
    case CAT1_CFG_SET:
        TRACE_I("mng dm %d CAT1_CFG_SET", from_module);
        resp_data = (void *)set_cat1_cfg((gw_cat1_cfg_t *)data, &is_reboot, &is_save_static);
        break;

    case BT_CFG_GET:
        TRACE_I("mng dm %d BT_CFG_GET", from_module);
        resp_data = (void *)get_bt_cfg();
        break;
    case BT_CFG_SET:
        TRACE_I("mng dm %d BT_CFG_SET", from_module);
        resp_data = (void *)set_bt_cfg((gw_bt_cfg_t *)data, &is_save_static);
        break;

    case MQTT_SERVER_CFG_GET:
        TRACE_I("mng dm %d MQTT_SERVER_CFG_GET", from_module);
        resp_data = (void *)get_mqtt_server_cfg();
        break;
    case MQTT_SERVER_CFG_SET:
        TRACE_I("mng dm %d MQTT_SERVER_CFG_SET", from_module);
        resp_data = (void *)set_mqtt_server_cfg((gw_mqtt_server_cfg_t *)data, &is_reboot, &is_save_static);
        break;

    case DATA_CFG_GET:
        TRACE_I("mng dm %d DATA_CFG_GET", from_module);
        resp_data = (void *)get_data_cfg();
        break;
    case DATA_CFG_SET:
        TRACE_I("mng dm %d DATA_CFG_SET", from_module);
        resp_data = (void *)set_data_cfg((gw_data_cfg_t *)data, &is_save_static);
        break;

    case WATCHDOG_CFG_GET:
        TRACE_I("mng dm %d WATCHDOG_CFG_GET", from_module);
        resp_data = (void *)get_wtd_cfg();
        break;
    case WATCHDOG_CFG_SET:
        TRACE_I("mng dm %d WATCHDOG_CFG_SET", from_module);
        resp_data = (void *)set_wtd_cfg((gw_wtd_cfg_t *)data, &is_reboot, &is_save_static);
        break;

    case GATEWAY_FTP_LOG_CFG_GET:
        TRACE_I("mng dm %d GATEWAY_FTP_LOG_CFG_GET", from_module);
        resp_data = (void *)get_gateway_ftp_log_cfg();
        break;
    case GATEWAY_FTP_LOG_CFG_SET:
        TRACE_I("mng dm %d GATEWAY_FTP_LOG_CFG_SET", from_module);
        resp_data = (void *)set_gateway_ftp_log_cfg((gw_ftp_log_cfg_t *)data, &is_save_static);
        break;

    case LOG_SWITCH_CFG_GET:
        TRACE_I("mng dm %d LOG_SWITCH_CFG_GET", from_module);
        resp_data = (void *)get_log_switch_cfg();
        break;
    case LOG_SWITCH_CFG_SET:
        TRACE_I("mng dm %d LOG_SWITCH_CFG_SET", from_module);
        resp_data = (void *)set_log_switch_cfg((gw_log_switch_cfg_t *)data, &is_save_static);
        break;

    case UART_485_CFG_GET:
        TRACE_I("mng dm %d UART_485_CFG_GET", from_module);
        resp_data = (void *)get_uart_485_cfg();
        break;
    case UART_485_CFG_SET:
        TRACE_I("mng dm %d UART_485_CFG_SET", from_module);
        resp_data = (void *)set_uart_485_cfg((gw_uart_485_cfg_t *)data, &is_save_static);
        break;

    case GATEWAY_TIMED_CFG_GET:
        TRACE_I("mng dm %d GATEWAY_TIMED_CFG_GET", from_module);
        resp_data = (void *)get_timed_cfg();
        break;
    case GATEWAY_TIMED_CFG_SET:
        TRACE_I("mng dm %d GATEWAY_TIMED_CFG_SET", from_module);
        resp_data = (void *)set_timed_cfg((gw_timed_cfg_t *)data, &is_save_static);
        break;

    case RESET_FACTORY:
        TRACE_I("mng dm %d RESET_FACTORY", from_module);
        resp_data = (void *)static_data_reset(&is_reboot);
        break;

    case GATEWAY_REBOOT:
        TRACE_I("mng dm %d GATEWAY_REBOOT", from_module);
        resp_data = (void *)gateway_reboot(&is_force_reboot);
        break;

    case ALL_CFG_GET:
        TRACE_I("mng dm %d ALL_CFG_GET", from_module);
        module_queue_communication(module_get_queue(from_module),
                                   GATEWAY_MANAGER_MODULE,
                                   NET_APP_MODULE,
                                   ALL_CFG_GET,
                                   RT_NULL);
        break;

    case UBOOT_CFG_GET:
        TRACE_I("mng dm %d UBOOT_CFG_GET", from_module);
        resp_data = (void *)get_uboot_cfg();
        break;
    case UBOOT_CFG_SET:
        TRACE_I("mng dm %d UBOOT_CFG_SET", from_module);
        resp_data = (void *)set_uboot_cfg((uboot_cfg_t *)data, &is_reboot);
        break;

    case IMMEDIATE_EFFECTIVE_GET:
        TRACE_I("mng dm %d IMMEDIATE_EFFECTIVE_GET", from_module);
        resp_data = (void *)get_immediate_effective_cfg();
        break;
    case IMMEDIATE_EFFECTIVE_SET:
        TRACE_I("mng dm %d IMMEDIATE_EFFECTIVE_SET", from_module);
        resp_data = (void *)set_immediate_effective_cfg((unsigned int *)data);
        break;

    case MSH_CMD_EXEC:
        TRACE_I("mng dm %d MSH_CMD_EXEC", from_module);
        resp_data = (void *)msh_cmd_exec((char *)data);
        break;

    case FACTORY_TEST_RESULT_GET:
        TRACE_I("mng dm %d FACTORY_TEST_RESULT_GET", from_module);
        resp_data = (void *)get_factory_test_result();
        break;

    case ONLINE_DEVICE_GET:
        TRACE_I("mng dm %d ONLINE_DEVICE_GET", from_module);
        resp_data = (void *)get_online_device_list();
        break;

    case GATEWAY_TIME_GET:
        TRACE_I("mng dm %d GATEWAY_TIME_GET", from_module);
        resp_data = (void *)get_gateway_time();
        break;

    case SYNC_CFG_GET:
        TRACE_I("mng dm %d SYNC_CFG_GET", from_module);
        resp_data = (void *)get_sync_cfg();
        break;
    case SYNC_CFG_SET:
        TRACE_I("mng dm %d SYNC_CFG_SET", from_module);
        resp_data = (void *)set_sync_cfg((sync_cfg_t *)data, &is_reboot, &is_save_static);
        break;

    case GATEWAY_AUTH_LIST_GET:
        TRACE_I("mng dm %d GATEWAY_AUTH_LIST_GET", from_module);
        resp_data = (void *)get_gateway_auth_list();
        break;

    case GATEWAY_SCAN_FREQ_REQ:
        TRACE_I("mng dm %d GATEWAY_SCAN_FREQ_REQ", from_module);
        resp_data = (void *)gateway_scan_freq_req((gw_scan_freq_req_t *)data);
        break;

    case GATEWAY_SCAN_FREQ_STOP:
        TRACE_I("mng dm %d GATEWAY_SCAN_FREQ_STOP", from_module);
        resp_data = (void *)gateway_scan_freq_stop();
        break;

    case SYNC_DYNAMICS_INFO_GET:
        TRACE_I("mng dm %d SYNC_DYNAMICS_INFO_GET", from_module);
        resp_data = (void *)get_sync_dynamics_info();
        break;

    default:
        break;
    }

    if (resp_data)
    {
        // 反馈设置结果
        if (0 != module_queue_communication(module_get_queue(from_module),
                                            GATEWAY_MANAGER_MODULE,
                                            from_module,
                                            cmd,
                                            resp_data))
        {
            rt_free(resp_data);
            resp_data = RT_NULL;
        }
    }

    // 配置改变，保存静态数据
    if (is_save_static)
    {
        uc_static_save_op();
    }

    // 鉴权信息改变，优先发送广播通知IoTE重新鉴权
    if (is_auth_change)
    {
        // 模拟WIoTa APP线程发送给自身线程，处理鉴权信息改变消息
        module_queue_communication(get_gateway_manager_queue(),
                                   WIOTA_APP_MODULE,
                                   GATEWAY_MANAGER_MODULE,
                                   AUTH_INFO_CHANGE,
                                   RT_NULL);
    }

    // 某些配置，设置完成后需要重启
    if ((g_immedicate_effect_flag && is_reboot) || is_force_reboot)
    {
        // 发给自身线程
        module_queue_communication(get_gateway_manager_queue(),
                                   GATEWAY_MANAGER_MODULE,
                                   GATEWAY_MANAGER_MODULE,
                                   GATEWAY_REBOOT,
                                   RT_NULL);
    }
}

void entry_factory(int argc, char *argv[])
{
    int ret = 0;
    gw_auth_cfg_t *gw_auth_cfg = RT_NULL;
    if (argc != 1)
    {
        TRACE_E("entry factory argc error");
        return;
    }

    gw_auth_cfg = uc_static_get_gateway_auth_cfg();
    gw_auth_cfg->work_mode = UC_FACTORY_MODE;
    uc_static_save_op();

    TRACE_E("gateway will entry factory test mode!!!\n");
}
MSH_CMD_EXPORT(entry_factory, entry factory test mode);

void restore_factory(int argc, char *argv[])
{
    uc_static_data_reset();
    uc_boot_cfg_reset();
    watchdog_reboot();
}
MSH_CMD_EXPORT(restore_factory, restore factory setting);

void entry_rf_test(int argc, char *argv[])
{
    gw_auth_cfg_t *gw_auth_cfg = uc_static_get_gateway_auth_cfg();
    wiota_ts_cfg_t *ts_cfg = uc_static_get_wiota_ts_cfg();
    gw_auth_cfg->work_mode = atoi(argv[1]);
    ts_cfg->ts_mode = UC_TS_SYNC_ASSISTANT;
    uc_static_save_op();
    TRACE_I("entry rf%d test mode!!!\n", gw_auth_cfg->work_mode);
    watchdog_reboot();
}
MSH_CMD_EXPORT(entry_rf_test, entry rf test setting);

void wifi_connect(int argc, char *argv[])
{
    int ret = 0;
    gw_wifi_cfg_t *gw_wifi_cfg = RT_NULL;

    if (argc != 3)
    {
        TRACE_E("wifi connect argc error");
        return;
    }

    gw_wifi_cfg = rt_calloc(1, sizeof(gw_wifi_cfg_t));
    if (RT_NULL == gw_wifi_cfg)
    {
        TRACE_E("wifi connect malloc failed");
        return;
    }

    rt_memcpy(gw_wifi_cfg, uc_static_get_gateway_wifi_cfg(), sizeof(gw_wifi_cfg_t));
    gw_wifi_cfg->static_ip = 0;
    rt_memset(gw_wifi_cfg->username, 0, sizeof(gw_wifi_cfg->username));
    rt_memset(gw_wifi_cfg->password, 0, sizeof(gw_wifi_cfg->password));
    rt_strncpy(gw_wifi_cfg->username, argv[1], rt_strlen(argv[1]));
    rt_strncpy(gw_wifi_cfg->password, argv[2], rt_strlen(argv[2]));

    ret = module_queue_communication(get_gateway_manager_queue(),
                                     SERIAL_DEBUG_MANAGER_MODULE,
                                     GATEWAY_MANAGER_MODULE,
                                     WIFI_CFG_SET,
                                     gw_wifi_cfg);

    if (ret != RT_EOK)
    {
        TRACE_E("wifi connect failed");
        if (RT_NULL != gw_wifi_cfg)
        {
            rt_free(gw_wifi_cfg);
            gw_wifi_cfg = RT_NULL;
        }
    }
}
MSH_CMD_EXPORT(wifi_connect, connect to wifi);
